An Authoritative Guide to CORS (Cross-Origin Resource Sharing) for REST APIs

Many modern Web applications (and their developers) depend on nearly frictionless and simultaneous access to Web APIs from multiple API providers. But like a firewall that closes off access to untrusted parties in the name of security, the Web's default is to prevent such "loose" behavior. Thankfully, that default can be securely overridden. However, it is incumbent on both the developers of Web applications and the API providers that service them to understand the principles of what is known as Cross-Origin Resource Sharing (CORS) before doing so.

CORS is a security mechanism that allows a Web page from one domain (aka an Origin) to access a resource from a different origin (what's known as a cross-domain request). Modern browsers normally reject such requests because they default to a "same-origin policy." CORS, therefore, is essentially a relaxation of that same-origin policy and without it, websites are restricted to accessing resources from the same origin.

The same-origin policy exists to prevent malicious behavior. Without same-origin policy, an attacker could do things like hijack authentication cookies to perform malicious behavior, such as withdrawing money from your bank account when you're signed into online banking. Let's walk through an example.

About the Same-origin Policy

Many websites use cookies to keep track of authentication or session info. Those cookies, typically viewable in list form through a browser's configuration dialogs, are bounded to a certain domain when they are created and issued to the browser. On every subsequent HTTP call to that domain, the browser will attach the cookies that were created for that domain. This is on every HTTP call be it for static images, HTML pages, or even AJAX calls.

This means when you log into https://examplebank.com, a cookie is stored in your browser for https://examplebank.com. If that bank is a React single-page app (SPA), they may have created a REST API at https://examplebank.com/api for the SPA to communicate via AJAX.

The CSRF Vulnerability Without a Same-origin Policy

Let's say you browse to the malicious website https://evilunicorns.com while logged into https://examplebank.com. Without the same-origin policy that hacker website could make authenticated malicious AJAX calls to the API's "withdraw funds" resource (i.e., POST /withdraw) at https://examplebank.com/api even though the hacker's website doesn't have direct access to the bank's cookies.

This is due to the browser behavior of automatically attaching any cookies bounded to https://examplebank.com for any HTTP calls to that domain, including AJAX calls from https://evilunicorns.com to https://examplebank.com. This type of attack is called Cross-Site Request Forgery (CSRF).

How Same-origin Prevents This Attack

By restricting HTTP calls to only ones to the same origin (i.e., the domain indicated in the URL field of the browser), the same-origin policy closes some of these hacker backdoors, such as this Cross-Site Request Forgery (CSRF) attack as the browser would not allow the https://evilunicorns.com to make AJAX calls to https://examplebank.com as these are two different origins.

How is Origin Defined?

So, what constitutes a unique origin? Origin refers to the content who initiated the request, which is usually the open browser tab, but it could also be the origin of an iFrame window. Origin includes a combination of protocol (e.g., http, ftp, etc.), domain, and port. This means that https://api.mydomain.com and https://mydomain.com are actually different origins and thus impacted by same-origin policy. In a similar way, http://localhost:9000 and http://localhost:8080 are also different origins. The path as well as any query parameters are ignored when considering the origin.

Why CORS Was Created

There are legitimate reasons for a website to make cross-origin HTTP requests. Maybe a single-page app at https://mydomain.com needs to make AJAX calls to https://api.mydomain.com or maybe https://mydomain.com incorporates some third-party fonts or analytics providers like Google Analytics or MixPanel. CORS securely enables these cross-domain requests.

 

Derric Gilling is the current CEO at Moesif, an error analysis and analytics platform for APIs, and based in San Francisco, CA. Derric also was the CTO at Trove Market and a computer architect at Intel on the Xeon Phi CPU. He studied Computer Engineering at the University of Michigan.

Comments