What all Developers need to know about: CORS

Posted by Simon Lenz on October 2, 2018

— 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.

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,

http://www.example.com/subdir

has the same origin, while both

http://nl.example.com  and  https://www.example.com

have different origins and fall therefore under the SOP.

This policy prevents scenarios like the following:

  1. you are logged in to  https://my-bank.com

  2. in another browser tab you go to  http://malicious-page.com

  3. malicious JavaScript code sends in the background a request to  https://my-bank.com  requesting all your money being transferred to the hacker’s bank account

  4. 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.

CORS

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  http://data.example.com  and  http://awesome-pictures.net .

Your browser automatically adds the HTTP header

Origin: http://www.example.com

to these secondary requests.

The server at  http://awesome-pictures.net  then responds with the actual requested picture and includes the HTTP header

Access-Control-Allow-Origin: http://www.example.com

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.

Flowchart that describes the browsers decision wheather to make a preflight request or just a normal request.
Browsers consideration wheather to make a preflight request (red box) or just a normal request (green box). [Source: Wikipedia CORS]

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.

Recommendations

  • 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 Access-Control-Allow-Origin: * to signal everybody can access. Examples would be an API endpoint that can be used by the whole world or a public CDN link for your favourite javascript library.

  • 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

 

Want to learn more about security? Find all our security blogs here: https://techblog.topdesk.com/tag/security/ or check out https://careers.topdesk.com/ for job vacancies and join our security team.

About the author: Simon Lenz

Software developer at TOPdesk with interests in elegant, self-explanatory code, Privacy and much more.

More Posts