Breaking down CORS

Breaking down CORS

·

7 min read

CORS or Cross Origin Resource Sharing can seem frustrating when you're first starting out with client side development, but fundamentally it exists to protect information and give server owners greater control over how their stuff is used.

To understand Cross Origin Resource Sharing, let's first break it down and understand the individual parts that make it up.

breaking-down-cors.png

Origin

Origin refers to a URL's scheme (HTTP or HTTPS), its full hostname (domain or subdomain), and its port (by default the port for HTTP is 80 and for HTTPS is 443. These ports do not need to be explicitly mentioned).

For example, let us consider Hashnode's URL: "https:// www. hashnode.com:443". The URL has a scheme of HTTPS, "www. hashnode.com" as the hostname and 443 as its port.

Two URLs are said to be of the same origin when they both have the same scheme, the same full hostname, and the same port.

This means that "hashnode.com/n/javascript" and "hashnode.com/n/reactjs" have the same origin - they have the same scheme (HTTPS), the same full hostname (hashnode.com), and the same port (an implicit port 443). The different paths to javascript and reactjs do not matter.

However, if any of the aforementioned three attributes differ for two URLs, they are considered to have different origins. Again, using Hashnode's URLs as examples: "https:// www. shahxcode.hashnode.dev/" and "https:// www. julia.hashnode.dev/" are of different origins because they have different subdomains which makes the full hostnames different. The schemes and ports for both domains are still the same.

When working locally, local servers running on different ports are of different origins.

Now that we understand what origin refers to, let's focus on the Resource part of CORS.

Resource

A resource is what the web server responds back with when it receives a request. The resource can be an HTML file, a JSON object, an image file, or anything else that you can request from a web server.

For example, a web server receives a request when you enter a URL in the browser, click on an embedded link or request a URL through the fetch method in the client-side code. When "hashnode.com" is entered in the browser, Hashnode's server responds with a resource which is the HTML file used for rendering Hashnode's homepage.

Putting it Together

Keeping in mind what Origin and Resource mean from the above sections, one can begin to understand what Cross Origin Resource Sharing means. It's about sharing resources - sending and receiving - across origins - between two origins that are different from one another.

Why do we need CORS

When we are using websites, our browser is storing cookies that are used for session information and authentication by the respective websites. Every single time we make a call to the domain of the website we are using, our browser sends the respective domain's cookies as part of the request to the web server. This helps the web server identify us and verify our session, among other things.

For instance, when we log into "hashnode.com", we have a cookie stored for our browsing session. You can view the cookies stored for Hashnode by visiting your browser's dev tool, going to the Application tab, and dropping down the menu for Storage.

However, this leaves us susceptible to vulnerability.

When accessing URLs through a browser, we as users can be tricked into making a request which we do not intend to make. A common way of doing this is by making a fetch request through the client-side JS when you visit a website. The website itself may seem innocuous and as a user, you will not even know that a fetch request has been made to a different URL unless you keep an eye on your network access tab. The browser will send the fetched website's session information in the request header, as it normally does for all requests. The web server which receives this sneaky fetch request cannot realize that it was sent without your permission and assumes you are a normal user requesting the URL resource. Between this transfer of data, the cookies sent in the request header can be sniffed and stored independently. The stored cookies can be used to access information while posing as a routine session of yours.

Let's consider an example. Suppose you click on a link shared in a Reddit comment and that link takes you to a website. When this website loads, a fetch request is sneakily made through the client-side Javascript to Reddit.com. You will not note this request being made. Your session information and other cookies are sent with this request to the Reddit web server. The Reddit web server assumes that it is a routine request made by you; it cannot figure out that this is a sneaky fetch request made without your consent. The session information from that request could be sniffed and sent to another computer from where it can be used to access your Reddit account as you.

With CORS, a website cannot use Javascript to request data from another origin unless the web server at that other origin explicitly permits it. This can be done by including a header in the response called Access-Control-Allow-Origin, which can be used to specify other origins which are allowed to request that specific resource.

Simply said, every web server has its own origin. If a request is sent from anywhere except for this origin, it will not be able to access the resource unless the web server explicitly allows it to.

If a URL is sending a request to a web server, but it does not have the same origin as that of the web server then it will not be able to access the server's response. In this case, you will get an error in the console and if you check the Network tab of your developer tool, you will notice the response headers don't include Access-Control-Allow-Origin.

Access-Control-Allow-Origin gives the web server control over which website can access the server. "Access-Control-Allow-Origin: *" in the response header will allow all and any origin to access the server. "Access-Control-Allow-Origin: reddit.com" will only allow Reddit to access the resource sent by the web server.

To learn more about the technical details of CORS and the functionality of the response headers, check out the MDN page about CORS.

Why does the server respond back with a resource at all?

When a request comes from an origin that is not whitelisted by the server, the server still responds back with the resource to the browser. This often leads to the question that why would a resource be sent at all?

For a browser, there is no way to differentiate requests. Whether you enter a URL in the browser, click on a link or get a sneaky fetch request running on your end, the browser sends the same request to the web server. Similarly, on the web server end, there is no way to tell if the request was initiated maliciously or intentionally.

The only point at which you can tell the difference is in the browser where the request came from, so that's why the web server responds back with the resource and its Access-Control-Allow-Origin list in the response header. If the origin is different/not permitted, the browser prevents the client-side Javascript from accessing the resource and throws an error.

Ending with an analogy

The majority of developers will deal with CORS issues at some point. However, when they do face CORS issues, they focus on bypassing the problems by trying different solutions listed on StackOverflow. While this approach may do the job, by doing this many developers remain unaware of what is happening, or rather, why certain things are happening. Hopefully, this article helps paint a big picture in your mind. Like with most things in tech, there are still many things within CORs that you can deep dive into.

Let's end the article with the Visa and Passport Control Analogy I came up with to remember how CORS works:

Mr. Request wants to go on a vacation, but the country he wants to visit requires a visa. So Mr. Request submits a visa application (request) at the embassy (web server). The visa officer takes Mr. Request's case and hands him the decision letter (response). When Mr. Request goes to the airport, the passport control checks the decision letter (checks Access-Control-Allow-Origin) to decide if Mr. Request can fly to the country (access the resource) or not.