| ===================================== |
| Cross Site Request Forgery protection |
| ===================================== |
| |
| .. module:: django.middleware.csrf |
| :synopsis: Protects against Cross Site Request Forgeries |
| |
| The CSRF middleware and template tag provides easy-to-use protection against |
| `Cross Site Request Forgeries`_. This type of attack occurs when a malicious |
| Web site contains a link, a form button or some javascript that is intended to |
| perform some action on your Web site, using the credentials of a logged-in user |
| who visits the malicious site in their browser. A related type of attack, |
| 'login CSRF', where an attacking site tricks a user's browser into logging into |
| a site with someone else's credentials, is also covered. |
| |
| The first defense against CSRF attacks is to ensure that GET requests are |
| side-effect free. POST requests can then be protected by following the steps |
| below. |
| |
| .. versionadded:: 1.2 |
| The 'contrib' apps, including the admin, use the functionality described |
| here. Because it is security related, a few things have been added to core |
| functionality to allow this to happen without any required upgrade steps. |
| |
| .. _Cross Site Request Forgeries: http://www.squarefree.com/securitytips/web-developers.html#CSRF |
| |
| How to use it |
| ============= |
| |
| .. versionchanged:: 1.2 |
| The template tag functionality (the recommended way to use this) was added |
| in version 1.2. The previous method (still available) is described under |
| `Legacy method`_. |
| |
| To enable CSRF protection for your views, follow these steps: |
| |
| 1. Add the middleware |
| ``'django.middleware.csrf.CsrfViewMiddleware'`` to your list of |
| middleware classes, :setting:`MIDDLEWARE_CLASSES`. (It should come |
| before ``CsrfResponseMiddleware`` if that is being used, and before any |
| view middleware that assume that CSRF attacks have been dealt with.) |
| |
| Alternatively, you can use the decorator |
| ``django.views.decorators.csrf.csrf_protect`` on particular views you |
| want to protect (see below). |
| |
| 2. In any template that uses a POST form, use the :ttag:`csrf_token` tag inside |
| the ``<form>`` element if the form is for an internal URL, e.g.:: |
| |
| <form action="" method="post">{% csrf_token %} |
| |
| This should not be done for POST forms that target external URLs, since |
| that would cause the CSRF token to be leaked, leading to a vulnerability. |
| |
| 3. In the corresponding view functions, ensure that the |
| ``'django.core.context_processors.csrf'`` context processor is |
| being used. Usually, this can be done in one of two ways: |
| |
| 1. Use RequestContext, which always uses |
| ``'django.core.context_processors.csrf'`` (no matter what your |
| TEMPLATE_CONTEXT_PROCESSORS setting). If you are using |
| generic views or contrib apps, you are covered already, since these |
| apps use RequestContext throughout. |
| |
| 2. Manually import and use the processor to generate the CSRF token and |
| add it to the template context. e.g.:: |
| |
| from django.core.context_processors import csrf |
| from django.shortcuts import render_to_response |
| |
| def my_view(request): |
| c = {} |
| c.update(csrf(request)) |
| # ... view code here |
| return render_to_response("a_template.html", c) |
| |
| You may want to write your own ``render_to_response`` wrapper that |
| takes care of this step for you. |
| |
| The utility script ``extras/csrf_migration_helper.py`` can help to automate the |
| finding of code and templates that may need to be upgraded. It contains full |
| help on how to use it. |
| |
| .. _csrf-ajax: |
| |
| AJAX |
| ---- |
| |
| While the above method can be used for AJAX POST requests, it has some |
| inconveniences: you have to remember to pass the CSRF token in as POST data with |
| every POST request. For this reason, there is an alternative method: on each |
| XMLHttpRequest, set a custom `X-CSRFToken` header to the value of the CSRF |
| token. This is often easier, because many javascript frameworks provide hooks |
| that allow headers to be set on every request. In jQuery, you can use the |
| ``ajaxSend`` event as follows: |
| |
| .. code-block:: javascript |
| |
| $(document).ajaxSend(function(event, xhr, settings) { |
| function getCookie(name) { |
| var cookieValue = null; |
| if (document.cookie && document.cookie != '') { |
| var cookies = document.cookie.split(';'); |
| for (var i = 0; i < cookies.length; i++) { |
| var cookie = jQuery.trim(cookies[i]); |
| // Does this cookie string begin with the name we want? |
| if (cookie.substring(0, name.length + 1) == (name + '=')) { |
| cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); |
| break; |
| } |
| } |
| } |
| return cookieValue; |
| } |
| function sameOrigin(url) { |
| // url could be relative or scheme relative or absolute |
| var host = document.location.host; // host + port |
| var protocol = document.location.protocol; |
| var sr_origin = '//' + host; |
| var origin = protocol + sr_origin; |
| // Allow absolute or scheme relative URLs to same origin |
| return (url == origin || url.slice(0, origin.length + 1) == origin + '/') || |
| (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') || |
| // or any other URL that isn't scheme relative or absolute i.e relative. |
| !(/^(\/\/|http:|https:).*/.test(url)); |
| } |
| function safeMethod(method) { |
| return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); |
| } |
| |
| if (!safeMethod(settings.type) && sameOrigin(settings.url)) { |
| xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')); |
| } |
| }); |
| |
| .. note:: |
| |
| Due to a bug introduced in jQuery 1.5, the example above will not work |
| correctly on that version. Make sure you are running at least jQuery 1.5.1. |
| |
| Adding this to a javascript file that is included on your site will ensure that |
| AJAX POST requests that are made via jQuery will not be caught by the CSRF |
| protection. |
| |
| The decorator method |
| -------------------- |
| |
| Rather than adding ``CsrfViewMiddleware`` as a blanket protection, you can use |
| the ``csrf_protect`` decorator, which has exactly the same functionality, on |
| particular views that need the protection. It must be used **both** on views |
| that insert the CSRF token in the output, and on those that accept the POST form |
| data. (These are often the same view function, but not always). It is used like |
| this:: |
| |
| from django.views.decorators.csrf import csrf_protect |
| from django.template import RequestContext |
| |
| @csrf_protect |
| def my_view(request): |
| c = {} |
| # ... |
| return render_to_response("a_template.html", c, |
| context_instance=RequestContext(request)) |
| |
| Use of the decorator is **not recommended** by itself, since if you forget to |
| use it, you will have a security hole. The 'belt and braces' strategy of using |
| both is fine, and will incur minimal overhead. |
| |
| Legacy method |
| ------------- |
| |
| In Django 1.1, the template tag did not exist. Instead, a post-processing |
| middleware that re-wrote POST forms to include the CSRF token was used. If you |
| are upgrading a site from version 1.1 or earlier, please read this section and |
| the `Upgrading notes`_ below. The post-processing middleware is still available |
| as ``CsrfResponseMiddleware``, and it can be used by following these steps: |
| |
| 1. Follow step 1 above to install ``CsrfViewMiddleware``. |
| |
| 2. Add ``'django.middleware.csrf.CsrfResponseMiddleware'`` to your |
| :setting:`MIDDLEWARE_CLASSES` setting. |
| |
| ``CsrfResponseMiddleware`` needs to process the response before things |
| like compression or setting ofETags happen to the response, so it must |
| come after ``GZipMiddleware``, ``CommonMiddleware`` and |
| ``ConditionalGetMiddleware`` in the list. It also must come after |
| ``CsrfViewMiddleware``. |
| |
| Use of the ``CsrfResponseMiddleware`` is not recommended because of the |
| performance hit it imposes, and because of a potential security problem (see |
| below). It can be used as an interim measure until applications have been |
| updated to use the :ttag:`csrf_token` tag. It is deprecated and will be |
| removed in Django 1.4. |
| |
| Django 1.1 and earlier provided a single ``CsrfMiddleware`` class. This is also |
| still available for backwards compatibility. It combines the functions of the |
| two middleware. |
| |
| Note also that previous versions of these classes depended on the sessions |
| framework, but this dependency has now been removed, with backward compatibility |
| support so that upgrading will not produce any issues. |
| |
| Security of legacy method |
| ~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| The post-processing ``CsrfResponseMiddleware`` adds the CSRF token to all POST |
| forms (unless the view has been decorated with ``csrf_response_exempt``). If |
| the POST form has an external untrusted site as its target, rather than an |
| internal page, that site will be sent the CSRF token when the form is submitted. |
| Armed with this leaked information, that site will then be able to successfully |
| launch a CSRF attack on your site against that user. The |
| ``@csrf_response_exempt`` decorator can be used to fix this, but only if the |
| page doesn't also contain internal forms that require the token. |
| |
| .. _ref-csrf-upgrading-notes: |
| |
| Upgrading notes |
| --------------- |
| |
| When upgrading to version 1.2 or later, you may have applications that rely on |
| the old post-processing functionality for CSRF protection, or you may not have |
| enabled any CSRF protection. This section outlines the steps necessary for a |
| smooth upgrade, without having to fix all the applications to use the new |
| template tag method immediately. |
| |
| First of all, the location of the middleware and related functions have |
| changed. There are backwards compatible stub files so that old imports will |
| continue to work for now, but they are deprecated and will be removed in Django |
| 1.4. The following changes have been made: |
| |
| * Middleware have been moved to ``django.middleware.csrf`` |
| * Decorators have been moved to ``django.views.decorators.csrf`` |
| |
| ====================================================== ============================================== |
| Old New |
| ====================================================== ============================================== |
| django.contrib.csrf.middleware.CsrfMiddleware django.middleware.csrf.CsrfMiddleware |
| django.contrib.csrf.middleware.CsrfViewMiddleware django.middleware.csrf.CsrfViewMiddleware |
| django.contrib.csrf.middleware.CsrfResponseMiddleware django.middleware.csrf.CsrfResponseMiddleware |
| django.contrib.csrf.middleware.csrf_exempt django.views.decorators.csrf.csrf_exempt |
| django.contrib.csrf.middleware.csrf_view_exempt django.views.decorators.csrf.csrf_view_exempt |
| django.contrib.csrf.middleware.csrf_response_exempt django.views.decorators.csrf.csrf_response_exempt |
| ====================================================== ============================================== |
| |
| You should update any imports, and also the paths in your |
| :setting:`MIDDLEWARE_CLASSES`. |
| |
| If you have ``CsrfMiddleware`` in your :setting:`MIDDLEWARE_CLASSES`, you will now |
| have a working installation with CSRF protection. It is recommended at this |
| point that you replace ``CsrfMiddleware`` with its two components, |
| ``CsrfViewMiddleware`` and ``CsrfResponseMiddleware`` (in that order). |
| |
| If you do not have any of the middleware in your :setting:`MIDDLEWARE_CLASSES`, |
| you will have a working installation but without any CSRF protection for your |
| views (just as you had before). It is strongly recommended to install |
| ``CsrfViewMiddleware`` and ``CsrfResponseMiddleware``, as described above. |
| |
| Note that contrib apps, such as the admin, have been updated to use the |
| ``csrf_protect`` decorator, so that they are secured even if you do not add the |
| ``CsrfViewMiddleware`` to your settings. However, if you have supplied |
| customised templates to any of the view functions of contrib apps (whether |
| explicitly via a keyword argument, or by overriding built-in templates), **you |
| MUST update them** to include the :ttag:`csrf_token` template tag as described |
| above, or they will stop working. (If you cannot update these templates for |
| some reason, you will be forced to use ``CsrfResponseMiddleware`` for these |
| views to continue working). |
| |
| Note also, if you are using the comments app, and you are not going to add |
| ``CsrfViewMiddleware`` to your settings (not recommended), you will need to add |
| the ``csrf_protect`` decorator to any views that include the comment forms and |
| target the comment views (usually using the :ttag:`comment_form_target` template |
| tag). |
| |
| Assuming you have followed the above, all views in your Django site will now be |
| protected by the ``CsrfViewMiddleware``. Contrib apps meet the requirements |
| imposed by the ``CsrfViewMiddleware`` using the template tag, and other |
| applications in your project will meet its requirements by virtue of the |
| ``CsrfResponseMiddleware``. |
| |
| The next step is to update all your applications to use the template tag, as |
| described in `How to use it`_, steps 2-3. This can be done as soon as is |
| practical. Any applications that are updated will now require Django 1.1.2 or |
| later, since they will use the CSRF template tag which was not available in |
| earlier versions. (The template tag in 1.1.2 is actually a no-op that exists |
| solely to ease the transition to 1.2 — it allows apps to be created that have |
| CSRF protection under 1.2 without requiring users of the apps to upgrade to the |
| Django 1.2.X series). |
| |
| The utility script ``extras/csrf_migration_helper.py`` can help to automate the |
| finding of code and templates that may need to be upgraded. It contains full |
| help on how to use it. |
| |
| Finally, once all applications are upgraded, ``CsrfResponseMiddleware`` can be |
| removed from your settings. |
| |
| While ``CsrfResponseMiddleware`` is still in use, the ``csrf_response_exempt`` |
| decorator, described in `Exceptions`_, may be useful. The post-processing |
| middleware imposes a performance hit and a potential vulnerability, and any |
| views that have been upgraded to use the new template tag method no longer need |
| it. |
| |
| Exceptions |
| ---------- |
| |
| .. versionchanged:: 1.2 |
| Import paths for the decorators below were changed. |
| |
| To manually exclude a view function from being handled by either of the two CSRF |
| middleware, you can use the ``csrf_exempt`` decorator, found in the |
| ``django.views.decorators.csrf`` module. For example:: |
| |
| from django.views.decorators.csrf import csrf_exempt |
| |
| @csrf_exempt |
| def my_view(request): |
| return HttpResponse('Hello world') |
| |
| Like the middleware, the ``csrf_exempt`` decorator is composed of two parts: a |
| ``csrf_view_exempt`` decorator and a ``csrf_response_exempt`` decorator, found |
| in the same module. These disable the view protection mechanism |
| (``CsrfViewMiddleware``) and the response post-processing |
| (``CsrfResponseMiddleware``) respectively. They can be used individually if |
| required. |
| |
| Subdomains |
| ---------- |
| |
| By default, CSRF cookies are specific to the subdomain they are set for. This |
| means that a form served from one subdomain (e.g. server1.example.com) will not |
| be able to have a target on another subdomain (e.g. server2.example.com). This |
| restriction can be removed by setting :setting:`CSRF_COOKIE_DOMAIN` to be |
| something like ``".example.com"``. |
| |
| Please note that, with or without use of this setting, this CSRF protection |
| mechanism is not safe against cross-subdomain attacks -- see `Limitations`_. |
| |
| Rejected requests |
| ================= |
| |
| By default, a '403 Forbidden' response is sent to the user if an incoming |
| request fails the checks performed by ``CsrfViewMiddleware``. This should |
| usually only be seen when there is a genuine Cross Site Request Forgery, or |
| when, due to a programming error, the CSRF token has not been included with a |
| POST form. |
| |
| No logging is done, and the error message is not very friendly, so you may want |
| to provide your own page for handling this condition. To do this, simply set |
| the :setting:`CSRF_FAILURE_VIEW` setting to a dotted path to your own view |
| function, which should have the following signature:: |
| |
| def csrf_failure(request, reason="") |
| |
| where ``reason`` is a short message (intended for developers or logging, not for |
| end users) indicating the reason the request was rejected. |
| |
| How it works |
| ============ |
| |
| The CSRF protection is based on the following things: |
| |
| 1. A CSRF cookie that is set to a random value (a session independent nonce, as |
| it is called), which other sites will not have access to. |
| |
| This cookie is set by ``CsrfViewMiddleware``. It is meant to be permanent, |
| but since there is no way to set a cookie that never expires, it is sent with |
| every response that has called ``django.middleware.csrf.get_token()`` |
| (the function used internally to retrieve the CSRF token). |
| |
| 2. A hidden form field with the name 'csrfmiddlewaretoken' present in all |
| outgoing POST forms. The value of this field is the value of the CSRF |
| cookie. |
| |
| This part is done by the template tag (and with the legacy method, it is done |
| by ``CsrfResponseMiddleware``). |
| |
| 3. For all incoming POST requests, a CSRF cookie must be present, and the |
| 'csrfmiddlewaretoken' field must be present and correct. If it isn't, the |
| user will get a 403 error. |
| |
| This check is done by ``CsrfViewMiddleware``. |
| |
| 4. In addition, for HTTPS requests, strict referer checking is done by |
| ``CsrfViewMiddleware``. This is necessary to address a Man-In-The-Middle |
| attack that is possible under HTTPS when using a session independent nonce, |
| due to the fact that HTTP 'Set-Cookie' headers are (unfortunately) accepted |
| by clients that are talking to a site under HTTPS. (Referer checking is not |
| done for HTTP requests because the presence of the Referer header is not |
| reliable enough under HTTP.) |
| |
| This ensures that only forms that have originated from your Web site can be used |
| to POST data back. |
| |
| It deliberately only targets HTTP POST requests (and the corresponding POST |
| forms). GET requests ought never to have any potentially dangerous side effects |
| (see `9.1.1 Safe Methods, HTTP 1.1, RFC 2616`_), and so a CSRF attack with a GET |
| request ought to be harmless. |
| |
| ``CsrfResponseMiddleware`` checks the Content-Type before modifying the |
| response, and only pages that are served as 'text/html' or |
| 'application/xml+xhtml' are modified. |
| |
| .. _9.1.1 Safe Methods, HTTP 1.1, RFC 2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html |
| |
| Caching |
| ======= |
| |
| If the :ttag:`csrf_token` template tag is used by a template (or the ``get_token`` |
| function is called some other way), ``CsrfViewMiddleware`` will add a cookie and |
| a ``Vary: Cookie`` header to the response. Similarly, |
| ``CsrfResponseMiddleware`` will send the ``Vary: Cookie`` header if it inserted |
| a token. This means that these middleware will play well with the cache |
| middleware if it is used as instructed (``UpdateCacheMiddleware`` goes before |
| all other middleware). |
| |
| However, if you use cache decorators on individual views, the CSRF middleware |
| will not yet have been able to set the Vary header or the CSRF cookie, and the |
| response will be cached without either one. In this case, on any views that |
| will require a CSRF token to be inserted you should use the |
| :func:`django.views.decorators.csrf.csrf_protect` decorator first:: |
| |
| from django.views.decorators.cache import cache_page |
| from django.views.decorators.csrf import csrf_protect |
| |
| @cache_page(60 * 15) |
| @csrf_protect |
| def my_view(request): |
| # ... |
| |
| |
| Testing |
| ======= |
| |
| The ``CsrfViewMiddleware`` will usually be a big hindrance to testing view |
| functions, due to the need for the CSRF token which must be sent with every POST |
| request. For this reason, Django's HTTP client for tests has been modified to |
| set a flag on requests which relaxes the middleware and the ``csrf_protect`` |
| decorator so that they no longer rejects requests. In every other respect |
| (e.g. sending cookies etc.), they behave the same. |
| |
| If, for some reason, you *want* the test client to perform CSRF |
| checks, you can create an instance of the test client that enforces |
| CSRF checks:: |
| |
| >>> from django.test import Client |
| >>> csrf_client = Client(enforce_csrf_checks=True) |
| |
| Limitations |
| =========== |
| |
| Subdomains within a site will be able to set cookies on the client for the whole |
| domain. By setting the cookie and using a corresponding token, subdomains will |
| be able to circumvent the CSRF protection. The only way to avoid this is to |
| ensure that subdomains are controlled by trusted users (or, are at least unable |
| to set cookies). Note that even without CSRF, there are other vulnerabilities, |
| such as session fixation, that make giving subdomains to untrusted parties a bad |
| idea, and these vulnerabilities cannot easily be fixed with current browsers. |
| |
| If you are using ``CsrfResponseMiddleware`` and your app creates HTML pages and |
| forms in some unusual way, (e.g. it sends fragments of HTML in JavaScript |
| document.write statements) you might bypass the filter that adds the hidden |
| field to the form, in which case form submission will always fail. You should |
| use the template tag or :meth:`django.middleware.csrf.get_token` to get |
| the CSRF token and ensure it is included when your form is submitted. |
| |
| Contrib and reusable apps |
| ========================= |
| |
| Because it is possible for the developer to turn off the ``CsrfViewMiddleware``, |
| all relevant views in contrib apps use the ``csrf_protect`` decorator to ensure |
| the security of these applications against CSRF. It is recommended that the |
| developers of other reusable apps that want the same guarantees also use the |
| ``csrf_protect`` decorator on their views. |