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

Commit

Permalink
fix: reject requests when cors origin list is empty (#3674)
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
3 people committed May 7, 2021
1 parent 511147b commit a8d7ac4
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 3 deletions.
42 changes: 39 additions & 3 deletions packages/ipfs-http-server/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,36 @@ async function serverCreator (serverAddrs, createServer, ipfs, cors) {
return servers
}

/**
* @param {string} [str]
* @param {string[]} [allowedOrigins]
*/
function isAllowedOrigin (str, allowedOrigins = []) {
if (!str) {
return false
}

let origin

try {
origin = (new URL(str)).origin
} catch {
return false
}

for (const allowedOrigin of allowedOrigins) {
if (allowedOrigin === '*') {
return true
}

if (allowedOrigin === origin) {
return true
}
}

return false
}

class HttpApi {
constructor (ipfs, options = {}) {
this._ipfs = ipfs
Expand Down Expand Up @@ -150,11 +180,17 @@ class HttpApi {

const headers = request.headers || {}
const origin = headers.origin || ''
const referrer = headers.referrer || ''
const referer = headers.referer || ''
const userAgent = headers['user-agent'] || ''

// If these are set, we leave up to CORS and CSRF checks.
if (origin || referrer) {
// If these are set, check them against the configured list
if (origin || referer) {
if (!isAllowedOrigin(origin || referer, cors.origin)) {
// Hapi will not allow an empty CORS origin list so we have to manually
// reject the request if CORS origins have not been configured
throw Boom.forbidden()
}

return h.continue
}

Expand Down
111 changes: 111 additions & 0 deletions packages/ipfs-http-server/test/cors.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,23 @@ describe('cors', () => {
}
}, { ipfs, cors: { origin: [origin] } })

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

it('allows request when referer is supplied in request', async () => {
const origin = 'http://localhost:8080'
const res = await http({
method: 'POST',
url: '/api/v0/id',
headers: {
referer: origin + '/index.html'
}
}, { ipfs, cors: { origin: [origin] } })

expect(res).to.have.property('statusCode', 200)
})

it('does not allow credentials when omitted in config', async () => {
const origin = 'http://localhost:8080'
const res = await http({
Expand Down Expand Up @@ -149,5 +163,102 @@ describe('cors', () => {

expect(res).to.have.property('statusCode', 404)
})

it('rejects requests when cors origin list is empty and origin is sent', async () => {
const origin = 'http://localhost:8080'
const res = await http({
method: 'POST',
url: '/api/v0/id',
headers: {
origin
}
}, {
ipfs,
cors: { origin: [] }
})

expect(res).to.have.property('statusCode', 403)
})

it('rejects requests when cors origin list is empty and referer is sent', async () => {
const referer = 'http://localhost:8080/index.html'
const res = await http({
method: 'POST',
url: '/api/v0/id',
headers: {
referer
}
}, {
ipfs,
cors: { origin: [] }
})

expect(res).to.have.property('statusCode', 403)
})

it('rejects requests when cors origin list is empty and referer and origin are sent', async () => {
const referer = 'http://localhost:8080/index.html'
const res = await http({
method: 'POST',
url: '/api/v0/id',
headers: {
referer,
origin: 'http://localhost:8080'
}
}, {
ipfs,
cors: { origin: [] }
})

expect(res).to.have.property('statusCode', 403)
})

it('rejects requests when cors origin list is empty and origin is sent as "null" (e.g. data urls and sandboxed iframes)', async () => {
const origin = 'null'
const res = await http({
method: 'POST',
url: '/api/v0/id',
headers: {
origin
}
}, {
ipfs,
cors: { origin: [] }
})

expect(res).to.have.property('statusCode', 403)
})

it('rejects requests when cors origin list does not contain the correct origin and origin is sent', async () => {
const origin = 'http://localhost:8080'
const res = await http({
method: 'POST',
url: '/api/v0/id',
headers: {
origin
}
}, {
ipfs,
cors: { origin: ['http://example.com:8080'] }
})

expect(res).to.have.property('statusCode', 403)
})

it('rejects requests when cors origin list does not contain the correct origin and referer is sent', async () => {
const referer = 'http://localhost:8080/index.html'
const res = await http({
method: 'POST',
url: '/api/v0/id',
headers: {
referer
}
}, {
ipfs,
cors: { origin: ['http://example.com:8080'] }
})

expect(res).to.have.property('statusCode', 403)
})
})
})

0 comments on commit a8d7ac4

Please sign in to comment.