Cross-Origin Resource Sharing (CORS)

Written by Ulises Gascón

Apr 08, 20203 min read

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