Common Origin Policy and CORS: A Visual Guide





Good day, friends!



I present to your attention the translation of the article "CS Visualized: CORS" by Lydia Hallie.



Every developer has had to deal with an error Access to fetched has been blocked by CORS policy. There are several ways to quickly solve this problem. However, let's take our time and take a closer look at what a CORS policy is.



We often need to display data that is located elsewhere. Before we can do this, the browser must send a request to the server to receive this data.



Let's say we want to get information about a user on our site www.mywebsite.comfrom a server located on the site api.website.com.







Excellent! We have just sent a request to the server and received JSON data in response.



Now let's try to send a similar request to another domain. Instead of sending a request with, let's www.mywebsite.comsend it with www.anotherdomain.com.







What happened? We sent the exact same request, but this time the browser shows some kind of error.



We're seeing CORS in action. Why did this error occur and what does it mean?



Common origin policy



There is something on the web called Generic Origin Policy (hereinafter referred to as POP). By default, we only have access to those resources that are in the same origin as the origin of our request. For example, we can load an image located in https://mywebsite.com/image1.png.



A source is different when it is located in a different (sub) domain, protocol, or port.







Cool, but why do you need POP?



Let's say it doesn't exist, and you accidentally click on a viral link that your aunt sent on Facebook. This link redirects you to a "malicious site" that has an embedded iframe that loads your bank's site and successfully logs in there using a cookie.



The developers of the "evil site" made sure that he had access to the iframe and could interact with the content of the DOM of your bank's site to transfer funds to his account on your behalf.







Yeah ... this is a serious security issue. We do not want anyone to have access to anything without our knowledge.



Fortunately, EPP exists. This policy restricts access to resources from other sources.







In this case, the source is www.evilwebsite.comtrying to access the resource from the source www.bank.com. EPP blocks this access and prevents bad site developers from accessing your banking data.



Okay, but ... how does it work?



Client side CORS



Even though EPP only applies to scripts, browsers "extend" it to any JavaScript requests: by default, we only have access to resources from one source.







Hmm, but ... we often need to get resources from another source. Perhaps our frontend needs to go to the server API to load data. To securely retrieve resources from other sources, browsers implement a mechanism called CORS.



CORS stands for Cross-Origin Resource Sharing. While browsers disallow resources from other sources, we can use CORS to change this restriction while staying safe.



User agents (browsers) can use CORS to allow cross-origin requests that would otherwise be blocked based on some HTTP response headers.



When a request is made to another source, the client automatically adds a header to the HTTP request Origin. The value of this header is the source of the request.







In order for the browser to allow retrieving resources from another source, the server's response must also contain a specific header.



Server side CORS



As backend developers, we can allow other sources to get our resources by including special headers starting with Access-Control-*. Based on the value of such headers, the browser allows resource sharing.



There are several CORS-headers, but one of them is a must: Access-Control-Allow-Origin.



The meaning of this header determines which sources can receive our resources.



If we are developing a server that needs to be accessible https://mywebsite.com, we have to add this domain to the header Access-Control-Allow-Origin.







Great. This header is now added to the server response sent to the client. EPP no longer prevents us from receiving resources https://api.mywebsite.comthrough requests sent from https://mywebsite.com.







Browser CORS checks that the response Access-Control-Allow-Originheader and the request header match Origin.



In this case, the source of our request is https://www.mywebsite.comthe response header specified in the list Access-Control-Allow-Origin.







Excellent. Now we can get resources from other sources. What happens if we try to do this from a source not listed in Access-Control-Allow-Origin?







Yes, CORS has blocked access to resources.



The 'Access-Control-Allow-Origin' header has a value
  'https://www.mywebsite.com' that is not equal 
to the supplied origin. 


In this case, the source is https://www.anotherwebsite.comnot listed in Access-Control-Allow-Origin. CORS has successfully denied the requested data.



CORS allows you to specify *allowed sources as a value. This means that the resources will be available to any source, so be careful.



Access-Control-Allow-OriginIs one of the many titles we can set. The back-end developer can configure CORS to allow (deny) specific requests.



Another common heading is Access-Control-Allow-Methods. CORS only allows requests from other sources that were sent using the specified methods.







In this case, only requests sent using the GET, POST or PUT methods are allowed. Other methods like PATCH or DELETE will be blocked.



CORS treats them in a special way when it comes to requests sent using the PUT, PATCH, and DELETE methods. These "tricky" queries are sometimes referred to as preflight queries.



Preliminary requests



CORS works with two types of requests: simple and provisional. What a query is depends on some of its values.



A request is simple if it is sent using the GET or POST methods and does not contain additional headers. Any other request is preliminary.



Okay, but what does pre-request mean and why are such requests needed?



Before sending the actual request, the client sends a preliminary request to the server with information about the actual request: about its method, additional headers, including Access-Control-Request-*, etc.







The server receives a provisional request and sends an empty provisional response containing CORS headers. The browser receives a provisional response and checks if the actual request will be allowed.







If so, then the browser sends the actual request and receives the data in response.







If not, CORS will block the pre-request and the actual request will not be sent. Pre-requests are a great way to prevent resources from being accessed and modified on the server. This protects the server from potentially unwanted requests from other sources.



To reduce the number of repeated requests, we can cache the provisional response by adding a header Access-Control-Max-Ageto the CORS request. This avoids re-sending the preliminary request.



Credentials



Cookies, authorization headers, and TLS certificates are installed by default only for requests from a single source. However, we may need to use these permissions in a request from another source. Perhaps we want to include cookies in the request that the server can use to identify the user.



Although CORS does not contain permissions by default, we can change this with a header Access-Control-Allow-Credentials.



If we want to include cookies and other authorization headers in our request from another source, we need to set the field to a withCredentialsvalue truein the request and add the header Access-Control-Allow-Credentialsto the response.







Done, now we can include credentials in our requests from another source.



I hope this article was helpful to you. Thank you for attention.



All Articles