What is Cross Origin Resource Sharing (CORS)?
1) What is the meaning of an Origin?
In web terminology, an origin refers to the unique identifier of the remote location (i.e. server) with which the transactions of the requests and responses take place. This unique identifier is particularly managed and used by the client (e.g. web browser).
The origin is constructed from the URL by the following factors-
- Protocol (http, https, ftp, etc)
- Hostname
- Port (which is by default 80 for HTTP and 443 for HTTPS, unless specified)
E.g. For the URL https://www.some-domain.in/path/to/the/resource, the origin is
[https, www.some-domain.in, 443]
2) Question?
Do the following URLs have the same origin as that of the URL mentioned in example of Section#1?
https://www.some-domain.in/some/asset/1
http://www.some-domain.in/path/to/the/resource
https://www.abc.some-domain.in/asset/2
https://www.some-domain.in:8342/some/js/file
https://www.some-domain.com/some/css/file
https://some-domain.com/some/css/file
3) What is the Same-Origin Policy?
Same-Origin Policy is a security mechanism that helps in preventing malicious web attacks.
Under same-origin policy, the client, generally a web browser, restricts the network call, originating from one origin, to a different origin.
Let’s understand that with an example.
- Suppose you hit https://www.some-site.com/ and the server returns the html document.
- During the parsing of this document, it encounters a URL for the JS file (https://www.some-site.com/main.js).
- The browser makes the network request and fetches that JS file.
- During parsing and execution of this JS file, there comes a place where the code is trying to make a GET http request to https://www.some-site.com/image1.
- The browser observes that the origin of the second URL is the same as the origin of the initial URL.
- Since it follows the same-origin policy, the browser will let this request through, and get image1.
Let's consider an extension of above example
- Suppose during parsing and execution of this JS file, there comes a place where the code is trying to make a POST http request to https://www.other-site.com/sendEvent with some payload.
- The browser observes that the origin of the second URL (https://www.other-site.com) is different from the origin of the initial URL (https://www.some-site.com/).
- Since it violates the same-origin policy, the browser blocks this network request.
4) What if browsers don’t follow the same-origin policy?
If the browsers do not follow the same-origin policy, that would mean any javascript code, emanating from one origin, can send a request to another origin. And this can open doors to security vulnerabilities, as explained below.
Let’s say you are logged into a banking site, https://www.bank-a.com. The information pertaining to the user authentication and session is stored as Cookie in the browser, along with other important information.
Now, suppose, you open a malicious website by accident which sends a javascript code back to the browser. That code calls the API https://www.bank-a.com/withdrawMoney which withdraws money from the bank account. Just hitting this API won't withdraw the money, because authentication and session info needs to be sent to validate the identity and session of the user.
But we know that the browser attaches the cookie info specific to an origin automatically with the request. So, while hitting the API https://www.bank-a.com/withdrawMoney from malicious site’s JS code, authentication and session info is automatically passed in Cookies HTTP Header in the request, leading to the withdrawal of the money.
This is one simple use-case where not having a same-origin policy can be lethal.
5) What is the downside of same-origin policy?
The downside of same-origin policy is that the website is unable to get/send the information from the authentic 3rd party service provider, on which your site is dependent upon.
E.g. Let’s assume your site has a form page, which captures the details of the potential customer-leads who are interested in availing your services. This data captured in this form is supposed to be sent to a Customer Management System(CMS). This system is hosted on a different server with a different URL. If the strict same-origin policy is enabled, then the request to submit the customer-leads data to the CMS won’t get through the browser. Here, some relaxation on the same-origin policy is needed.
6) CORS is the solution!
Taking into account section #4 and #5, we absolutely need to have a same-origin policy, but with some relaxation.
This is where Cross Origin Resource Sharing (CORS) policy comes into the picture !
Under CORS policy, browsers allow the transaction of requests and responses with whitelisted origins (i.e. few allowed origins), from the initial origin.
In the next section, let’s see how it is done.
7) How are cross-origin requests validated?
Before sending the actual request to a different origin than the current one, a preflight request is sent to the server.
A Preflight request -
- Is like a “probing” request, whose purpose is to find out whether the actual request can be catered by the server or not.
- Has the HTTP Request Method as OPTIONS.
- Has one HTTP Request Header namely ORIGIN, whose values contain the origin from where the request is being generated.
The response of the Preflight request contains HTTP Response Header namely ACCESS-CONTROL-ALLOW-ORIGIN, which contains a single origin value, or an asterisk (*) as the wildcard value.
After receiving the preflight response, the browser checks whether the value of ORIGIN in HTTP Request Header is the same as the value of ACCESS-CONTROL-ALLOW-ORIGIN HTTP Response Header or not.
If both the values are same, then the browser will allow the actual request’s network call. Otherwise, it will throw the familiar CORS error.
So, this is how browsers decide whether to allow a cross-origin request or not.
Please note that the actual request also contains ORIGIN HTTP Request Header and ACCESS-CONTROL-ALLOW-ORIGIN HTTP Response Header.
Note :
If you are Backend Developer, then exercise caution while sending the value of ACCESS-CONTROL-ALLOW-ORIGIN header as * (wildcard value), as it may open the door to other security vulnerabilities. Always send back a specific whitelisted origin.
Something worth noting is that preflight requests are not always sent by the browser.
When the request is not a simple-request , then only the preflight request is sent.
Refer the following link to know the criterias for a simple request.
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests
8) What kind of request uses CORS?
CORS mechanism is enabled for the following type of requests -
- Requests made by fetch() and XMLHTTPRequest
- Web Fonts (for cross-domain font usage in @font-face within CSS
- Images and Videos drawn to a canvas using drawImage()
For full list, refer the following URL
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#what_requests_use_cors
9) CORS specific HTTP Headers
For Request -
- Origin
- Access-Control-Request-Method
- Access-Control-Request-Headers
For Response -
- Access-Control-Allow-Origin
- Access-Control-Expose-Headers
- Access-Control-Max-Age
- Access-Control-Allow-Credentials
- Access-Control-Allow-Methods
- Access-Control-Allow-Headers
Refer the following excerpt to know more about these headers -
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#the_http_response_headers
10) Important Takeaways
- Assets (such as CSS, JS, Images etc), that are part of the HTML document (index.html) and have cross-origin URLs, gets downloaded without going through the CORS barrier.
- As mentioned in Section#8, only requests made by fetch() and XMLHTTPRequest API, and few others, goes through the CORS check in case of cross-origin requests.
- Preflight request is triggered when the request is not a simple request.
(Try adding a custom header in a call made by fetch API for cross-origin requests and observe that preflight request will be triggered)