DEV Community

Jordan Finneran
Jordan Finneran

Posted on • Originally published at jordanfinners.dev

Clarifying CORS - Cross-origin Resource Sharing

Contents

  1. Intro
  2. Access-Control Headers
  3. Rate Limiting
  4. Summary

Intro

Continuing on from my previous blog about website security week, we're going to talk about a CORS on the web.

CORS is Cross-origin Resource Sharing this is often used when your website is hosted separately from your API. e.g. your website is at website.com and calls your API at api.com.
This is a common architectural pattern as it allows each API and website to move independently and faster, however it can introduce some security issues.

Access-Control Headers

To allow CORS requests your API will need to response with certain headers, which allow certain behaviors from your website/frontend.

Access-Control-Allow-Origin

This header can be set with either the origin which will be calling the API, it can only be a single origin.
Otherwise it can be a * however this doesn't allow credentials to be passed, which we will talk about later.

If at all possible prefer setting a specific origin to a *.

Example Usage:

Access-Control-Allow-Origin: https://mozilla.org
Enter fullscreen mode Exit fullscreen mode




Access-Control-Allow-Methods

This header can be set with a list of HTTP Methods that are allowed to be used to contact your API.

Generally speaking OPTIONS will want to be part of this list as any frontend will make a OPTIONS request, often referred to as a preflight request, before it makes the actual request. OPTIONS requests won't be made for GET requests.

It can also be * however, you should be specific if you can.

Example Usage:

Access-Control-Allow-Methods: POST, GET, OPTIONS
Enter fullscreen mode Exit fullscreen mode




Access-Control-Max-Age

This header can be set to a time period that the frontend will cache the preflight OPTIONS request. It is a value in seconds for example 86400 seconds is 24 hours.

Let's say you've set Max-Age to the above, this means that the first request you make from the frontend to the API will make an OPTIONS request and then the actual request. It will subsequently won't have to make another OPTIONS request to that API for 24 hours.

Example Usage:

Access-Control-Max-Age: 86400
Enter fullscreen mode Exit fullscreen mode




Access-Control-Allow-Headers

This header can be set with a list of Headers that are allowed to be passed onto your API.

Example Usage:

Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Enter fullscreen mode Exit fullscreen mode




Access-Control-Allow-Credentials

This header specifies if to include credentials in the request. Credentials count as cookies, authorization headers or TLS client certificates.

Example Usage:

Access-Control-Allow-Credentials: true
Enter fullscreen mode Exit fullscreen mode




Rate Limiting

You should note that Access-Control-Allow-Origin header only prevents browsers from making requests to the API. It does not prevent calls to your API from other machines, command line, Postman etc.
You should ensure that you have put other security measures in place to prevent misuse of your API, including Authentication and Rate Limiting.

Rate Limiting involves restricting too many calls being made to your API. It can be done in a number of ways depending on how your API is developed. I would look for libraries to help manage this for you.

Summary

In summary, separating your API and website can produce real development benefits however it can introduce security problems and having to deal with CORS.
Hopefully this helps clarify CORS and how you can secure it.

Set those headers now!

Happy Building!

Top comments (1)

Collapse
 
alexparra profile image
Alex Parra • Edited

Hi!
A few notes...

OPTIONS requests won't be made for GET requests.

OPTIONS can be made for GET requests if they are not โ€œsimpleโ€.
See: developer.mozilla.org/en-US/docs/W...

You should note that Access-Control-Allow-Origin header only prevents browsers from making requests to the API.

The browser still always makes the GET/POST/XXX request.
If CORS fails the browser blocks the received response.
From the API standpoint CORS is never evaluated and these requests show in logs as successful regardless of CORS failures.