Skip to content
This repository was archived by the owner on Feb 12, 2024. It is now read-only.

Commit 0b2d98c

Browse files
achingbrainvasco-santoslidel
authored
fix: reject requests when cors origin list is empty (#3674)
If CORS origin list is empty, Hapi throws an error as it considers that to be invalid configuration. We want to reject requests that send and origin or a referer when no allowed origins have been configured, so when these headers are sent, reject the request if no allowed origins are present in the config. Co-authored-by: Vasco Santos <[email protected]> Co-authored-by: Marcin Rataj <[email protected]>
1 parent 46618c7 commit 0b2d98c

File tree

2 files changed

+150
-3
lines changed

2 files changed

+150
-3
lines changed

packages/ipfs-http-server/src/index.js

+39-3
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,36 @@ async function serverCreator (serverAddrs, createServer, ipfs, cors) {
5858
return servers
5959
}
6060

61+
/**
62+
* @param {string} [str]
63+
* @param {string[]} [allowedOrigins]
64+
*/
65+
function isAllowedOrigin (str, allowedOrigins = []) {
66+
if (!str) {
67+
return false
68+
}
69+
70+
let origin
71+
72+
try {
73+
origin = (new URL(str)).origin
74+
} catch {
75+
return false
76+
}
77+
78+
for (const allowedOrigin of allowedOrigins) {
79+
if (allowedOrigin === '*') {
80+
return true
81+
}
82+
83+
if (allowedOrigin === origin) {
84+
return true
85+
}
86+
}
87+
88+
return false
89+
}
90+
6191
class HttpApi {
6292
/**
6393
* @param {IPFS} ipfs
@@ -175,11 +205,17 @@ class HttpApi {
175205

176206
const headers = request.headers || {}
177207
const origin = headers.origin || ''
178-
const referrer = headers.referrer || ''
208+
const referer = headers.referer || ''
179209
const userAgent = headers['user-agent'] || ''
180210

181-
// If these are set, we leave up to CORS and CSRF checks.
182-
if (origin || referrer) {
211+
// If these are set, check them against the configured list
212+
if (origin || referer) {
213+
if (!isAllowedOrigin(origin || referer, cors.origin)) {
214+
// Hapi will not allow an empty CORS origin list so we have to manually
215+
// reject the request if CORS origins have not been configured
216+
throw Boom.forbidden()
217+
}
218+
183219
return h.continue
184220
}
185221

packages/ipfs-http-server/test/cors.js

+111
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,23 @@ describe('cors', () => {
3232
}
3333
}, { ipfs, cors: { origin: [origin] } })
3434

35+
expect(res).to.have.property('statusCode', 200)
3536
expect(res).to.have.nested.property('headers.access-control-allow-origin', origin)
3637
})
3738

39+
it('allows request when referer is supplied in request', async () => {
40+
const origin = 'http://localhost:8080'
41+
const res = await http({
42+
method: 'POST',
43+
url: '/api/v0/id',
44+
headers: {
45+
referer: origin + '/index.html'
46+
}
47+
}, { ipfs, cors: { origin: [origin] } })
48+
49+
expect(res).to.have.property('statusCode', 200)
50+
})
51+
3852
it('does not allow credentials when omitted in config', async () => {
3953
const origin = 'http://localhost:8080'
4054
const res = await http({
@@ -149,5 +163,102 @@ describe('cors', () => {
149163

150164
expect(res).to.have.property('statusCode', 404)
151165
})
166+
167+
it('rejects requests when cors origin list is empty and origin is sent', async () => {
168+
const origin = 'http://localhost:8080'
169+
const res = await http({
170+
method: 'POST',
171+
url: '/api/v0/id',
172+
headers: {
173+
origin
174+
}
175+
}, {
176+
ipfs,
177+
cors: { origin: [] }
178+
})
179+
180+
expect(res).to.have.property('statusCode', 403)
181+
})
182+
183+
it('rejects requests when cors origin list is empty and referer is sent', async () => {
184+
const referer = 'http://localhost:8080/index.html'
185+
const res = await http({
186+
method: 'POST',
187+
url: '/api/v0/id',
188+
headers: {
189+
referer
190+
}
191+
}, {
192+
ipfs,
193+
cors: { origin: [] }
194+
})
195+
196+
expect(res).to.have.property('statusCode', 403)
197+
})
198+
199+
it('rejects requests when cors origin list is empty and referer and origin are sent', async () => {
200+
const referer = 'http://localhost:8080/index.html'
201+
const res = await http({
202+
method: 'POST',
203+
url: '/api/v0/id',
204+
headers: {
205+
referer,
206+
origin: 'http://localhost:8080'
207+
}
208+
}, {
209+
ipfs,
210+
cors: { origin: [] }
211+
})
212+
213+
expect(res).to.have.property('statusCode', 403)
214+
})
215+
216+
it('rejects requests when cors origin list is empty and origin is sent as "null" (e.g. data urls and sandboxed iframes)', async () => {
217+
const origin = 'null'
218+
const res = await http({
219+
method: 'POST',
220+
url: '/api/v0/id',
221+
headers: {
222+
origin
223+
}
224+
}, {
225+
ipfs,
226+
cors: { origin: [] }
227+
})
228+
229+
expect(res).to.have.property('statusCode', 403)
230+
})
231+
232+
it('rejects requests when cors origin list does not contain the correct origin and origin is sent', async () => {
233+
const origin = 'http://localhost:8080'
234+
const res = await http({
235+
method: 'POST',
236+
url: '/api/v0/id',
237+
headers: {
238+
origin
239+
}
240+
}, {
241+
ipfs,
242+
cors: { origin: ['http://example.com:8080'] }
243+
})
244+
245+
expect(res).to.have.property('statusCode', 403)
246+
})
247+
248+
it('rejects requests when cors origin list does not contain the correct origin and referer is sent', async () => {
249+
const referer = 'http://localhost:8080/index.html'
250+
const res = await http({
251+
method: 'POST',
252+
url: '/api/v0/id',
253+
headers: {
254+
referer
255+
}
256+
}, {
257+
ipfs,
258+
cors: { origin: ['http://example.com:8080'] }
259+
})
260+
261+
expect(res).to.have.property('statusCode', 403)
262+
})
152263
})
153264
})

0 commit comments

Comments
 (0)