A Dangerous World
For example, without the same-origin policy, any website could make a request to your bank to transfer money, and the bank would not be able to tell the difference between that request and the one coming from its own website.
Yet, with the same-origin policy and no CORS, websites would not be able to use resources from another server apart from their own. For example, websites could not use a headless CMS for their content.
To understand how a website could make a request to our bank and impersonate us, we need to understand cookies. Cookies are pieces of data stored in the headers of any request, and the browsers persist them in further requests to that same domain.
For example, if a user logs in to "mybank.com" and the server there sets the header cookie to "token=session-open," the browser will always send this information when making a request to "mybank.com," whether the request is done in the same "mybank.com" website or from "demon.me."
This is the default behavior in browsers, at least for now.
The Same-Origin Policy
The solution to this cookie exploit is the same-origin policy. This policy is the browser's default behavior and restricts how a document or script can interact with a resource from another domain (or origin).
With this policy in place, when a user enters "demon.me" and the website tries to make a call to "mybank.com", the browser will stop it. The browser identifies that the user is in "demon.me" and the request is to another origin ("mybank.com"); therefore, not allowed.
What if that is what we want?
Yet, sometimes a website needs to make a call to another origin. And it's not trying to trick the user; it just needs some data, for example, data from a headless CMS.
The browser's same-origin policy blocks the request as if it was the exploitation explained before.
CORS stands for Cross-Origin Resource Sharing, and it was implemented precisely to solve this need while keeping the same-origin policy in place.
MDN explains it very nicely.
CORS is an HTTP header-based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources.
In a nutshell, a few headers can be set so that the browser does not follow the same-origin policy and makes requests to other origins. The main header of this mechanism is "Access-Control-Allow-Origin."
For example, a user enters "myweb.com," and the website makes a request to "mycms.com.", where the server sets the header "Access-Control-Allow-Origin: myweb.com." Therefore, telling the browser that the requests to "mycms.com" from "myweb.com" are allowed.
The Best of Both Worlds
The combination of the same-origin policy and CORS ensures that the users are protected and at the same time allows the internet players freedom and flexibility.
This solution was not as straightforward as it might seem. The same-origin policy was introduced in 1995, whereas the first draft of CORS was submitted in 2006. A situation we now consider evident took more than ten years to develop. In retrospect, everything seems obvious.
If you like this post, consider sharing it with your friends on twitter or forwarding this email to them 🙈
Don't hesitate to reach out to me if you have any questions or see an error. I highly appreciate it.
And thanks to Michal and Sebastià for reviewing this article 🙏
Thanks for reading, don't be a stranger 👋
GIMTEC is the newsletter I wish I had earlier in my software engineering career.
Every other Wednesday, I share an article on a topic that you won't learn at work.
Join more than 3,000 subscribers below.