— This post is part of a series of monthly blog posts about all kinds of Security topics for Developers —
In today’s article, we want to have a closer look at cross-origin resource sharing to see how it can help making your web application a little safer. Or more correctly, help giving you more control over the security of your application.
But before we can dive into talking about CORS, we need to explain the SOP.
The acronym stands for Same-Origin-Policy and is a security concept build in browsers to prevent information from one context – let’s say online banking – being accessible to another context like a malicious hacker site.
More specifically, it prevents a website to access data on a different origin. Origin is hereby defined as the combination of the URI scheme, the host name and the port number. Regarding this definition and taking
http://www.example.com as a reference,
has the same origin, while both
have different origins and fall therefore under the SOP.
This policy prevents scenarios like the following:
you are logged in to
in another browser tab you go to
https://my-bank.comrequesting all your money being transferred to the hacker’s bank account
because the browser automatically adds the session cookie to that request, your bank recognizes you as logged in and conducts the transactions
This attack exploits the trust that a site (the bank) has in a user’s browser and is called session riding which is a form of CSRF.
A browser that implements the SOP would prevent this very simple attack by not executing the background request to the bank’s website, because it has a different origin than the malicious page.
So far so good.
The problem is that this is far too restrictive for the real world. Not just since the ominous Web 2.0 and the rise of Ajax-based applications these cross-origin requests are found all over the Internet.
And that is where cross-origin resource sharing aka. CORS comes into play. It is a mechanism for relaxing the SOP. There is an important thing to notice here, namely that CORS does not increase the security of your application but in a way rather decreases it. In reality it gives you control over what you allow and what not, which is a very good thing to have.
The CORS standard specifies interaction between the browser and the server via HTTP headers to determine whether it is safe to allow the cross-origin request.
In the simplest case CORS specifies the request header
Origin by which the browser tells the server to respond with CORS in mind and the response header
Access-Control-Allow-Origin by which the server can signal, what the allowed origins are.
A brief example
You open a webpage like
http://www.example.com in your browser. This website itself wants to load some resources from
Your browser automatically adds the HTTP header
to these secondary requests.
The server at
http://awesome-pictures.net then responds with the actual requested picture and includes the HTTP header
to the response.
Your browser is now able to check if the actual origin of the request matches the origins returned from the secondary server. If yes, the browser will make the content of the response available to the application. If not, access will be denied.
This leads to the obvious question, why can’t we make this check on the server and don’t send the picture at all if the origins don’t match?
A hacker could easily craft its own HTTP request with his/her own headers at a whim. The server has no way to verify that the contents of the
Origin is really what it claims to be. The browser on the other hand can verify this, because he knows the real origin. And it’s not possible to tamper with it if the browser does everything correctly. That’s why the client is responsible for enforcing the CORS mechanism.
More complex requests
For requests without side effects on the server like your typical GET request, this is sufficient. But what about PUT and others? When the server’s response reaches the client, it is already too late, because the resource was already changed on the server.
Here comes another concept – the preflight request – into play. With this, the browser automatically precedes the actual request with an OPTIONS request. This preflight request is then answered by the server with the usual
Access-Control-Allow-Origin header. Only after the browser verified that the actual request will be allowed, he sends it. This extra request prevents therefore unwanted side-effects of the actual request in case it will be blocked by the SOP.
In the end everything is of course a little bit more complex. Besides the two HTTP headers already seen, CORS specifies more headers for even more control over what you allow and what not. You can for example specify allowed HTTP methods and headers as well as special handling for requests with authentication credentials.
The default should always be no header at all. With this, the SOP will be most restrictive.
For a publicly – without any access control checks – accessible resource, you can always safely return
Allow only selected and trusted domains and most importantly,
don’t use the
*wildcard blindly in order to “make it work”.
SOP and CORS don’t release you from having proper CSRF protection.
SOP and CORS are no access control. They only help protecting the user by preventing unwanted requests. Securing the resource on the server is still task of the server itself.
Simple requests (especially GET) shouldn’t have side effects on the server, since there is no preflight request that prevents the actual request from being sent.
Sources of this article