At some point in your journey of developing web applications, you will run into an error in your console, along the lines of Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at...
, and wonder what it means.
For a new JavaScript developer, this usually happens when they are making
a request to an API, either their own or someone else's, and they are confused what to do with the error.
TL;DR
- To understand CORS errors, it helps to first understand the Same-Origin Policy (SOP), as CORS is a server configuration to relax SOP.
- Same-Origin Policy is a browser security measure. Among other things, it was implemented to keep malicious websites and code, from abusing trusted sites (such as your bank and social media) that remember your login information.
- Servers configure their CORS settings based on who they expect to receive requests from.
- If a server has not been configured to receive requests from a particular front end, the browser will be unable to interact with it.
- It is a security issue to blindly apply a wildcard
'*'
CORS header to your servers if they are in production. - CORS and SOP have little to do with Cross-Site Request Forgery (CSRF), and a poorly configured SOP policy can actually make CSRF attacks easier.
Obviously a quick google can solve the problem: "If you control the server, have it set the Access-Control-Allow-Origin
header to the domain hosting your front end code, or you can set it to a wildcard '*'
, and solve all your problems. This post will try to help you understand why this is required in the first place.
If you're anything like me the first time I ran into this, it seemed a little confusing:
- Why does the server set this header in the response?
- How does the server controlling things make my front end app safer?
- What is the point of this header?
To understand this better, I'm going to introduce another acronym: SOP. It stands for Same-Origin Policy. It's a rule that, put simply, states:
"One domain + port combination cannot read the response to a request from a different domain + port combination."
The bolded part is important: any site can still make requests to another, but the response cannot be read by the domain that initiated the request.
Let's talk about the significance of this rule. Obviously it has to do with security. But what, specifically?
When you login to a website, they return a cookie to your browser which will be sent alongside future requests to represent authentication. Think of it as your browsers access card to restricted urls.
Imagine that on my blog, I have scripts that run in the background, and when you visit, I send a GET request to all of the common banking sites, via your browser. Your cookies will be sent along with this request. The landing page will be different for a logged in user, and so, if I can read the response, I can figure out what site you are logged in with, making it easier for me to target you in a phishing attack. If you are logged into Royal Bank of Canada, I could then try to get you to navigate to a page that looks like their login page, to see if I can steal your credentials.
This is one specific example, but the generalized goal is this: protect one resource/webpage from unintentionally leaking information to another.
How does CORS relate to all of this?
SOP dates back to Netscape in 1995. Back in the 90s, webpages were used completely different from how they are today. jQuery wasn't released until 2006, so, I think it's safe to say that dynamic, application-like webpages were not that common. Pages were generally static webpages. The Same-Origin Policy wasn't really counting on a world of Single-Page Applications interacting with an external API via fetch calls.
Cross-Origin Resource Sharing (CORS), was introduced as a way of relaxing the out-of-the-box restrictiveness of the Same-Origin Policy, by allowing the server to whitelist the origins (protocol + domain + port) which can interact with it. It is trying to protect servers from unintentionally leaking data to any ol' website. Your bank only wants to allow scripts running from their domains to read the data from their servers.
See this in action: Open the network tab of your browser's dev tools, filter by XHR, and navigate to any online banking site login page. Pick a request, and look in the Response Headers
section, for the header Access-Control-Allow-Origin
. Secure websites should specifically list only their login page there, which keeps malicious websites from being able to read data from their resources.
CORS and SOP are not making your front end app safer.
This is all to say: when you get the error in your console while developing an application, it is not telling you that there is a security flaw. Only that your server has not returned the CORS header telling the browser that your frontend is safe to read your server's data.
Remember, CORS and SOP are not making your front end app safer. SOP protects users from malicious websites. You are likely not building a malicious website, and so the CORS configuration is a formality to allow your front-end to read data from your server.
And when configuring Cross-Origin Requests: be specific about the domain, unless your server is expected to work with every piece of front end code out there (which is not usually the case, unless you have a public API).
There are more details, which I've brushed over to keep the concepts simple. For more information on the implementation, I encourage you to read the docs on SOP and CORS. Keep in mind, there is historical significance in design of CORS to make it backwards compatible with legacy servers wh ich were running before its release.
Originally posted on www.joshhogg.com
Top comments (1)
Such a helpful breakdown, thanks Josh.