CORS, You're Probably Doing it Wrong

Jun 6, 2020 min read

CORS TL;DR

Don’t do Access-Control-Allow-Origin: *❗❗

CORS What is it?

Cross-Origin Resource Sharing (CORS) is a way for resources to be shared between domains. A domain is considered to be different when the domain, port, or protocol are not the same as the requesting domain. For example, a single page web application might be available at https://mywebapp.com and the application could request data from https://api.mywebapp.com, because the two origins are different this request would be cross-domain and would cause an error if not properly configured.

CORS Why do we need it?

As our systems become more distributed we need to communicate and share resources across origins, this is what Cross-Origin Resource Sharing is meant to solve.

CORS vs. Same-Origin

The Same-Origin policy allows requests from a domain to the same domain to be allowed. This is a security feature of modern browsers. An example request might include a script on a domain making an XMLHttpRequest to the same domain. If the same script were to make a request to a different domain (domain, port, protocol) then the request is considered to be cross origin (or cross-domain) and would need to be handled properly by both the browser and server or it would fail. CORS allows use to make requests across origins that were restricted by the Same-Origin Policy.

CORS Common Mistakes

The most common CORS mistake security experts see when it comes to dealing with CORS and CORS errors is the broad whitelisting of access to resources. In most application server this is a configuration that looks like this: Access-Control-Allow-Origin: *. Allowing any external resource to make requests to internal resources through the * wildcard definition can have very adverse effects. For example, if we host an API server at https://api.mywebapp.com and our have server has CORS configured with Access-Control-Allow-Origin: *, we can now receive and have to process requests from http://evil-website.com which can flood our systems with requests and reduce our capacity for legitimate requests. Properly configured CORS allows us to prevent the additional request processing reducing a number of vulnerabilities.

Most often an application server, our API server for example, will and should only be receiving requests from one or more resources that we manage, like our single-page web application. Rarely do servers need to receive and process requests from unknown external origins. This is more of a use case for publicly available APIs. A more secure approach to configure CORS for your web application would be to create a list of only the allowed origins.

Configuring CORS for a NodeJS application

In this section we’ll take a quick look at how to configure the CORS NPM module in a NodeJS application to maximize the security of our application. For a more detailed overview, a tutorial on configuring CORS is available here: Tutorial: Configuring CORS in NodeJS

app.js

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

const app = express();
const port = process.env.PORT || 5000;

const allowedOrigins = ['http://localhost:8080', 'http://127.0.0.1:8080', 'http://localhost:4444'];

const corsOptions = {
  origin: (origin, callback) => {
    // When accessed from localhost the origin will be undefined, we need to look at the Referrer header
    if (allowedOrigins.indexOf(origin) !== -1) {
      callback(null, true)
    } else {
      callback(new Error('Not allowed by CORS'))
    }
  }
}

app.use(cors(corsOptions));

...

const server = app.listen(port, () => {
  console.log(`Server is listening on port: ${server.address().port}`)
});