Skip to main content

HTTP Header: CORS

CORS Meme Image from Joe Honton | A Series of Unhappy Events in Corslandia

What?​

CORS Meme Image from portswigger | Cross-origin resource sharing (CORS)

Cross-origin resource sharing (CORS) is a browser mechanism which enables controlled access to resources located outside of a given domain. It extends and adds flexibility to the same-origin policy (SOP). However, it also provides potential for cross-domain based attacks, if a website's CORS policy is poorly configured and implemented. CORS is not a protection against cross-origin attacks such as cross-site request forgery (CSRF). by portswigger | Cross-origin resource sharing (CORS)

The header​

In order to manage CORS we need to use several headers that have a common pattern Access-Control-*

  • Access-Control-Allow-Origin: indicates whether the response can be shared with requesting code from the given origin. Valid values (single url, * or null). See Documentation
  • Access-Control-Allow-Credentials: tells browsers whether to expose the response to frontend JavaScript code when the request's credentials mode (Request.credentials) is include. See Documentation
  • Access-Control-Allow-Methods: response header specifies the method or methods allowed when accessing the resource in response to a preflight request. See Documentation

There are other headers like Access-Control-Allow-Headers, Access-Control-Expose-Headers, Access-Control-Max-Age... used for CORS preflight requests

The code​

There is an official Middleware made by the Express team called CORS

Simple Usage​

const express = require('express')
const cors = require('cors')
const app = express()

app.use(cors())

app.get('/products/:id', (req, res, next) => {
res.json({ msg: 'This is CORS-enabled for all origins!' })
})

app.listen(8080, () => {
console.log('CORS-enabled web server listening on port 80')
})

Configuring CORS w/ Dynamic Origin​

const express = require('express')
const cors = require('cors')
const app = express()

const whitelist = ['http://example1.com', 'http://example2.com']

const corsOptions = {
origin: (origin, cb) => {
whitelist.includes(origin)
? cb(null, true)
: cb(new Error('Not allowed by CORS'))
}
}

app.get('/products/:id', cors(corsOptions), (req, res, next) => {
res.json({ msg: 'This is CORS-enabled for a whitelisted domain.' })
})

app.listen(8080, () => {
console.log('CORS-enabled web server listening on port 80')
})

Don't forget to check the configuration features

Attacks​

Most of the CORS attacks are based on generating a response header that allow the attackers to add their malicious domain in the Access-Control-Allow-Origin.

In most of the cases this flaws are generated by misconfiguration.

Solution​

  • Never use the Request origin value as the response Access-Control-Allow-Origin value.
  • Avoid wildcard validation like *-website.com, as the malicious attacks can match the criteria ( good-website.com, evil-website.com...).
  • Avoid to whitelist null as valid Origin value in the request header.
  • Avoid wildcards in internal networks

Refs​