A complete guide to CORS!

Anusha Dasari
6 min readJan 11, 2021

--

Am sure every developer must have either heard the term or has come across some annoying issues in the name of CORS. If you are one who’s usually perplexed with the idea of CORS or is haunted by the mysterious bugs blabbering something about CORS and never understood what they mean or how to resolve, this article is for you.

Am sure by the end of this, you will be at a great place, confident enough to tackle any CORS issues which you might encounter and hopefully helps make CORS a little less daunting, and also helps to securely configure CORS support to your own systems.

Is Application security important?

OfCORS it is. If you think otherwise, I guess you are on the wrong topic here and feel free to carry on with your firefighting. Or should I say bugfighting? Meh!

Why do I need to know about it?

Cross-Origin Request Site is an OWASP TOP 10 Security Misconfiguration vulnerability. In the process of enabling information sharing between sites, people tend to overlook the significance of CORS configuration. As developers, it’s very important that you are aware of this vulnerability and how it can be exploited.

What is this CORS?

CORS is abbreviation for Cross Origin Resource Sharing.

The idea behind CORS is simple: allow one site to make a request to another. It’s a fairly trivial thing to do from most programming languages. So why all this fuss around it?

While other programming languages have no restrictions on HTTP requests, things are different in a browser, where the browser’s same-origin policy prevents requests from different sites. CORS must balance the need to enable cross-origin requests while preserving the same-origin policy for sites that don’t use CORS.

This may make CORS sound like a contradiction. How can CORS allow cross-origin requests if the same-origin policy explicitly forbids them? The key is that CORS puts servers firmly in charge of who can make requests, and what type of requests are allowed. A server has the choice to open up its API to all clients, open it up to a small number of clients, or prevent access to all clients.

CORS is a unique web technology in that it has both a server-side and a client-side component. The server-side component configures which types of cross-origin requests are allowed, while the client-side component controls how cross-origin requests are made.

So if you want a brief overview of the entire journey of a CORS request, here it goes!

1. The CORS request is initiated by the JavaScript client code.

2. The browser includes additional HTTP headers on the request before sending the request to the server.

3. The server includes HTTP headers in the response that indicate whether the request is allowed.

4. If the request is allowed, the browser sends the response to the client code.

If the headers returned by the server don’t exist, or aren’t what the browser expects, the response is rejected and the client can’t view the response. In this way, browsers can still enforce the same-origin policy on servers that don’t allow cross-origin requests.

Still confused? Let’s look at it in a little bit detail.

Before that let’s understand a bit of the terminology.

What is the origin?

A request is a same-origin request when the client origin and the server origin are exactly the same. Otherwise the request is a cross-origin request.

Client Side:

While ancient browsers do not support making requests across different origins, in the current interconnected day and age, all modern browsers have support for Cross Origin requests.

  1. Client creates the request
  • The client specifies data such as the url, method, body and header to be sent with the request

2. Browser validates headers to be sent

  • The browser creates a request object that encompasses the request made by the client.
  • Any custom headers need to be confirmed with the server, resulting in a preflight request, which we will see shortly

3. Attach cookies and authorisation details

  • If credentials are included with the request (credentials are cookies, authorisation headers or TLS client certificates), they are sent with the request as well.

4. Browser validates and passes response to client (if allowed)

  • The browser checks the response from the server and decides whether or not to pass on the response to the client. By default, only Cache-Control, Content-Language, Content-Length, Content-Type, Expires, Last-Modified and Pragma headers are exposed to the client, unless specified in the Access-Control-Expose-Headers header.

Now let’s have a look at what happens on the server side

Server Side:

As seen above, you must have realised how the Browser is a trusted intermediary, and plays an active role in a CORS request in two ways:

  • The browser adds additional information to the request so that the server can identify the client.
  • The browser interprets the server’s response and decides whether to send the request to the client or to return an error.

So it is the server setting these following headers mainly, behind the scenes which is the core concept of CORS.

  • Origin header is always present on cross-origin requests
  • Value of the Access-Control-Allow-Origin header can be either a wildcard or an origin value

Example: Access-Control-Allow-Origin: *

or Access-Control-Allow-Origin: http://localhost:8080

“*” or wildcard header doesn’t necessarily mean that it’s publicly accessible. There may be additional forms of authentication on the resource

So when the origin header is something the server recognises, or is part of “Access-Control-Allow-Origin” , the server accepts the request, else it rejects it.

So how do we reject the request?

  • Sending an Access-Control-Allow-Origin header that doesn’t match the Origin header
  • Removing the Access-Control-Allow-Origin header entirely
  • This mechanism for rejecting CORS requests also protects servers that are not CORS aware

Example:

You must have come across this following error, and now you understand what it means.

What’s preflight request?

  • The browser sends a preflight request to ask the server for permission to make the actual request when using non simple methods or adding custom headers
  • protects servers from receiving unexpected requests.
  • takes the form of an HTTP OPTIONS method with an Origin and Access-Control-Request-Method header.
  • The server can grant permissions to use certain HTTP methods by using the Access-Control-Allow-Methods header. The server can also grant permission to use certain HTTP headers by using the Access-Control-Allow-Headers header.
  • The preflight result cache is a performance optimisation that helps reduce the number of preflight requests made to a particular endpoint.

Cookie support:

  • The Access-Control-Allow-Credentials header can be used in conjunction with withCredentials property to include cookies on cross-origin requests.
  • The Access-Control-Expose-Headers header can be used to expose response headers to the client.

Now that we understand the jargon and the headers, let’s look at best practices to set these headers in your applications for the best security.

Access-Control-Allow-Origin:

  • Use the * value to allow requests from all origins.
  • Use a whitelist to allow only certain origins.

Access-Control-Allow-Credentials:

  • Setting the value to true allows cookies on requests.
  • Enable cookies only if you’re sure you need them.
  • If your server does support cookies, be sure to also validate the origin and implement CSRF protection.

Access-Control-Allow-Methods:

  • This header only needs to be present on preflight responses.
  • It indicates which HTTP methods are allowed on a URL. Common values include HEAD, OPTIONS, GET, POST, PUT, PATCH, and DELETE.

Access-Control-Allow-Headers:

  • This header only needs to be present on preflight responses.
  • It indicates which HTTP headers are allowed on a URL.
  • Echo the Access-Control-Request-Headers value to get full header support.

Access-Control-Max-Age:

  • This header only needs to be present on preflight responses.
  • It indicates how many seconds to cache preflight requests for.
  • Browsers may have their own maxAge caps.

Access-Control-Expose-Headers:

  • This header indicates which response headers to expose to clients.
  • It’s an optional header that isn’t required for a successful CORS request.

Hope that gave you a fair idea of CORS to help you be equipped with the necessary details to deal with CORS in the future.

--

--