Django CORS

Filipe Ximenes
March 17, 2015
<p>It’s common among web developers, and mainly the ones who are developing web APIs, to face problems related to CORS. According to Wikipedia:</p><p>Cross-origin resource sharing (CORS) is a mechanism that allows many resources (e.g. fonts, JavaScript, etc.) on a web page to be requested from another domain outside the domain from which the resource originated.</p><p>Too complicated? Don't worry. We will explain.</p><h3 id="why-do-we-need-cors">Why do we need CORS?</h3><p>Because of the same-origin policy. This is a security concept implemented in all modern browsers, which prevent a website from loading data from another website. For a concrete example, imagine the following scenario:</p><ol><li>You visit a malicious website.</li><li>This website has a Javascript which makes a GET request to www.facebook.com/messages.</li><li>Since you are probably logged in in Facebook, without same-origin policy, this malicious Javascript would be able to read your Facebook messages then send it to the hackers!</li></ol><p>To see same-origin policy in action, you can browse to jquery.com and try to make a AJAX GET request to another domain. Since the request is made in the context of jquery.com, you will get an error from your browser:</p><figure class="kg-card kg-image-card"><img src="https://vinta-cms.s3.amazonaws.com/media/filer_public/3b/7e/3b7e9fb5-7bf4-4040-afa0-56dad7881cfc/django-cors-example-1.png" class="kg-image" alt="example-1" title="XMLHttpRequest cannot load http://en.wikipedia.org/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://jquery.com' is therefore not allowed access."></figure><p>You may try the same as above in a localhost webpage, with your own code making a request to Wikipedia. Again, because of the same origin policy, you will get an error from your browser.</p><p>But what about RESTful APIs? RESTful APIs usually implement CORS, which allows requests from other origins. For example, any website can make a AJAX GET request to httpbin.org:</p><figure class="kg-card kg-image-card"><img src="https://vinta-cms.s3.amazonaws.com/media/filer_public/bb/54/bb546689-7481-46b0-a3e3-9d4e9106a902/django-cors-example-2.png" class="kg-image" alt="pull-left example-1"></figure><p>CORS permits the browser to request data like XML or JSON from a website that is not the one the user is currently in. This behaviour prevents some security issues like XSS (Cross-site scripting), where a malicious site could send requests to your website using user’s credentials (like his session cookie) to fetch secure data or perform some action in his name.</p><h3 id="so-how-does-it-works">So, how does it works?</h3><p>Some people mistakenly think that allowing CORS is a frontend task when it’s actually implemented in the backend. Frontend developers do not have to perform special requests to access cross origin data. When a browser sends a request to a server it automatically sets some HTTP headers like the “Origin” header that tells the server from which site the request came from.<br>Knowing the origin, the server can block the request if it's unauthorized or set the proper headers so the browser knows the request was accepted. As we can see, CORS is an agreement between the browser and the server that does not involves the client application.<br>It’s also worth noticing that CORS has no effect on clients outside from the browser since they won't prevent the access of requested data by the application.</p><h3 id="how-to-enable-cors-in-django">How to enable CORS in Django?</h3><p>There’s a great Django app to help us with this task, it’s called <a href="https://github.com/ottoyiu/django-cors-headers">Django CORS headers</a> will allow us not only to set the required headers but will also allow us to tell which urls will be CORS enabled.<br>Lets suppose you have a fully functional Django site and is now building an API to be consumed by external sites. The urls.py file looks like this:</p><pre><code class="language-python"># coding: utf-8 from django.conf.urls import patterns, include, url from django.contrib import admin urlpatterns = patterns('', url(r'^admin/', include(admin.site.urls)), url(r'^', include('my_app.urls')), url(r'^api/v1/', include('api_v1_app.urls')), ) </code></pre><p>As you can see, all API urls will begin with “www.mydomain.com/api/v1/“. This is very good since we don’t want to enable CORS on the whole website, only to the API urls.<br>After going through django-cors-headers setup, we can add the following configurations to <code>settings.py</code>:</p><pre><code class="language-python">CORS_URLS_REGEX = r'^/api/v1/.*$' CORS_ORIGIN_ALLOW_ALL = True </code></pre><p>The first one restricts CORS only to our API and the second tells that any website can perform requests to our API. And that’s it, we are done!</p><h4 id="some-important-notes-">Some important notes:</h4><ul><li>There are a couple other configurations in the Django CORS headers lib that you can use to adapt it to your needs.</li><li>Unless you really know what your are doing, never enable CORS to the whole website, this is a serious security flaw.</li><li>Allowing CORS and using session cookie authentication in your API is also a security flaw. Instead, use something else like a token based authentication.</li></ul>