CORS for dummies

It all started with JavaScript support for browsers. JavaScript brought with it amazing new features e.g. dynamic contents, event based programming, DOM(Document Object Model) manipulation etc. Along with all these, came serious security concerns. What if an attacker.com tries to steal bank details from your-bank.com while you are logged in or tries to access DOM contents, using JavaScript.

SOP (Same Origin Policy) to the rescue

“ The same-origin policy is a critical security mechanism that restricts how a document or script loaded from one origin can interact with a resource from another origin”. Origin is defined as combination of scheme(protocol) , host(domain) and port of the web contents URL.

http(protocol)://localhost(domain):8080(port)

SOP restricts attacker.com from accessing your-bank.com DOM using JavaScript. SOP prevents the use of XMLHttpRequest to access resource from origin 1 to origin 2(protocol+domain+port).

But SOP can not block every cross origin request, otherwise a web page will static and alone :) . Below are the few scenarios in which SOP does allow cross origin request:

1. Cross-origin writes are typically allowed. Examples are links, redirects, and form submissions. With exception of some condition which i will discuss in a while.

2. Cross-origin embedding is typically allowed. Examples include JavaScript with <script src=”….”></script>, Image displayed in <img> , media played by <video> and <audio> , anything embedded by <frame> and <iframe>

It is important to understand why cross origin writes like form submissions is allowed under SOP. Under form submission it is not possible to access the response using front end JavaScript, browsers blocks it. But cross origin form submit also give way to certain attacks like CSRF.

Browsers blocks the front end JavaScript code from accessing the response in case of cross origin embedding too. Embed the below image tag into your web page

<img src=”https://www.imperva.com/learn/wp-content/uploads/sites/13/2019/01/sorted-XSS.png"></img>

and look at the network tab.

Can you notice the no response data available in the response tab, even then your web page will have the image embedded in it. Enough of explaining SOP, in an article which is titled as CORS.

CORS the savior

In modern web applications, cross origin HTTP requests initiated using scripts have become an important part of it. CORS was created to allow these cross origin requests safely. Its time for the definition of CORS.

Cross-Origin Resource Sharing is a mechanism that uses additional HTTP headers to tell a browser to let a web application running at one origin have permission to access selected resources from a server at a different origin.

Whenever a cross origin HTTP request is initiated using XmlHttpRequest or Fetch API, CORS gets activated and it look for two scenarios:

  1. Whether the request is a simple (will explain in a bit) request. If so, look for Access-Control-Allow-Origin (ACAO) header in the response. If the response contains the ACAO header with value as requesting origin then allow the script to access it, otherwise browser will block the JavaScript from accessing the response.
  2. If request is not a simple request, then browser will initiate a preflight ( again will explain in a bit) request to check weather the requesting origin(origin A) is allowed to make request to the requested origin(origin B). After origin B confirms that origin A can access its resources using result of preflight request, then browser will make a HTTP request for the resources on origin B.

Now lets delve into the details of first scenario, which needs explanation of simple request.

Simple Request

A simple request is the one which meets all the below criteria:

  1. Only allowed HTTP request methods are GET, HEAD and POST
  2. Apart from the headers set automatically by the user agent or browser (e.g. Connection, User-Agent) , the only headers which are allowed to be manually set are Accept, Accept-Language, Content-Language, Content-Type, Viewport-Width
  3. The only allowed values for the Content-Type header are application/x-www-form-urlencoded , multipart/form-data , text/plain

Below is a simple GET request using XMLHttpRequest. Lets see the request and response to understand what happens.

var xhr = new XMLHttpRequest();
xhr.open(‘GET’, ‘
https://people.googleapis.com/v1/people/me/connections');
xhr.send();

Above request satisfy the conditions for Simple request. Note the access-control-allow-origin header in the response having value https://developer.mozilla.org . ACAO header can also be * which means any origin can request resources from the other origin.

Preflighted Request

Preflighted requests first send an HTTP request by the OPTIONS method to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests are preflighted like this since they may have implications to user data.

A request is preflighted if any of the below conditions are true:

  1. If the request uses any of the following methods PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH
  2. of if, Apart from the headers set automatically by the user agent or browser (e.g. Connection, User-Agent) , request contains headers other than following Accept, Accept-Language, Content-Language, Content-Type, Viewport-Width
  3. or if, the Content-Type header has a value OTHER THAN the following application/x-www-form-urlencoded , multipart/form-data , text/plain

Let us modify the GET request used in simple request to add a content-type header with value application/json

var xhr = new XMLHttpRequest();
xhr.open(‘GET’, ‘
https://people.googleapis.com/v1/people/me/connections');
xhr.setRequestHeader(‘content-type’, ‘application/json’);
xhr.send();

Since the content-type header is application/json which is not in the set {application/x-www-form-urlencoded , multipart/form-data , text/plain} , browser will initiate a prelight request with request method as OPTIONS.

Note the response header of this preflighted request.

access-control-allow-headers: content-type — Indicates this HTTP header will be used when making the actual request

access-control-allow-methods: DELETE,GET,HEAD,PATCH,POST,PUTMethods allowed when accessing the resources

access-control-allow-origin: https://developer.mozilla.orgAllowed origin to access the response

access-control-max-age: 3600Caching duration of result of preflighted request i.e. no preflight request would be initiated if the same cross origin request is made again in the mentioned duration.

Original request will be made for the resources based on the result of preflighted request.

One other CORS header that is very important is access-control-allow-credential (ACAC). Lets see what this is all about.

Access-Control-Allow-Credential

Suppose you are on http://example.com and making a request to http://foo.com using XMLHttpRequest like below

var xhr = new XMLHttpRequest();
xhr.open(‘GET’, ‘
http://foo.com/', true);
xhr.withCredentials = true;
xhr.send();

This is a simple request, so browser will not initiate preflight request. Pay attention to the line xhr.withCredentials = true , this particular line tells the browser to include cookies, authorization headers or TLS client certificates, when making the cross origin request. If the foo.com respond with access-control-allow-origin as * or example.com then, this request will be an authenticated request and authenticated resources will be leaked.

To prevent this situation access-control-allow-credential header is used in the response. It has only two values true or false. If this header is set to false, front end JavaScript code will not be able to access the response of the request which contain xhr.withCredentials = true. Thus preventing the situation of leaked authenticated resources like API keys.

That’s it for now.

Give me a clap if you like the article, otherwise save it for my future article :)

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store