| ===================================== |
| 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 (and other |
| 'safe' methods, as defined by 9.1.1 Safe Methods, HTTP 1.1, |
| :rfc:`2616#section-9.1.1`) are side-effect free. Requests via 'unsafe' methods, |
| such as POST, PUT and DELETE, can then be protected by following the steps |
| below. |
| |
| .. _Cross Site Request Forgeries: http://www.squarefree.com/securitytips/web-developers.html#CSRF |
| |
| .. _using-csrf: |
| |
| How to use it |
| ============= |
| |
| 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 any view middleware that assume that CSRF attacks have |
| been dealt with.) |
| |
| Alternatively, you can use the decorator |
| :func:`~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 |
| :func:`~django.shortcuts.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 these steps. 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. |
| |
| As a first step, you must get the CSRF token itself. The recommended source for |
| the token is the ``csrftoken`` cookie, which will be set if you've enabled CSRF |
| protection for your views as outlined above. |
| |
| .. note:: |
| |
| The CSRF token cookie is named ``csrftoken`` by default, but you can control |
| the cookie name via the :setting:`CSRF_COOKIE_NAME` setting. |
| |
| Acquiring the token is straightforward: |
| |
| .. code-block:: javascript |
| |
| // using jQuery |
| 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; |
| } |
| var csrftoken = getCookie('csrftoken'); |
| |
| The above code could be simplified by using the `jQuery cookie plugin |
| <http://plugins.jquery.com/cookie/>`_ to replace ``getCookie``: |
| |
| .. code-block:: javascript |
| |
| var csrftoken = $.cookie('csrftoken'); |
| |
| .. note:: |
| |
| The CSRF token is also present in the DOM, but only if explicitly included |
| using :ttag:`csrf_token` in a template. The cookie contains the canonical |
| token; the ``CsrfViewMiddleware`` will prefer the cookie to the token in |
| the DOM. Regardless, you're guaranteed to have the cookie if the token is |
| present in the DOM, so you should use the cookie! |
| |
| .. warning:: |
| |
| If your view is not rendering a template containing the :ttag:`csrf_token` |
| template tag, Django might not set the CSRF token cookie. This is common in |
| cases where forms are dynamically added to the page. To address this case, |
| Django provides a view decorator which forces setting of the cookie: |
| :func:`~django.views.decorators.csrf.ensure_csrf_cookie`. |
| |
| Finally, you'll have to actually set the header on your AJAX request, while |
| protecting the CSRF token from being sent to other domains. |
| |
| .. code-block:: javascript |
| |
| function csrfSafeMethod(method) { |
| // these HTTP methods do not require CSRF protection |
| return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); |
| } |
| function sameOrigin(url) { |
| // test that a given url is a same-origin 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)); |
| } |
| $.ajaxSetup({ |
| beforeSend: function(xhr, settings) { |
| if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) { |
| // Send the token to same-origin, relative URLs only. |
| // Send the token only if the method warrants CSRF protection |
| // Using the CSRFToken value acquired earlier |
| xhr.setRequestHeader("X-CSRFToken", 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. |
| |
| You can use `settings.crossDomain <http://api.jquery.com/jQuery.ajax>`_ in |
| jQuery 1.5 and newer in order to replace the `sameOrigin` logic above: |
| |
| .. code-block:: javascript |
| |
| function csrfSafeMethod(method) { |
| // these HTTP methods do not require CSRF protection |
| return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); |
| } |
| $.ajaxSetup({ |
| crossDomain: false, // obviates need for sameOrigin test |
| beforeSend: function(xhr, settings) { |
| if (!csrfSafeMethod(settings.type)) { |
| xhr.setRequestHeader("X-CSRFToken", csrftoken); |
| } |
| } |
| }); |
| |
| .. note:: |
| |
| In a `security release blogpost`_, a simpler "same origin test" example |
| was provided which only checked for a relative URL. The ``sameOrigin`` |
| test above supersedes that example—it works for edge cases like |
| scheme-relative or absolute URLs for the same domain. |
| |
| .. _security release blogpost: https://www.djangoproject.com/weblog/2011/feb/08/security/ |
| |
| Other template engines |
| ---------------------- |
| |
| When using a different template engine than Django's built-in engine, you can |
| set the token in your forms manually after making sure it's available in the |
| template context. |
| |
| For example, in the Cheetah template language, your form could contain the |
| following: |
| |
| .. code-block:: html |
| |
| <div style="display:none"> |
| <input type="hidden" name="csrfmiddlewaretoken" value="$csrf_token"/> |
| </div> |
| |
| You can use JavaScript similar to the :ref:`AJAX code <csrf-ajax>` above to get |
| the value of the CSRF token. |
| |
| The decorator method |
| -------------------- |
| |
| .. module:: django.views.decorators.csrf |
| |
| 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). |
| |
| Use of the decorator by itself is **not recommended**, 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. |
| |
| .. function:: csrf_protect(view) |
| |
| Decorator that provides the protection of ``CsrfViewMiddleware`` to a view. |
| |
| Usage:: |
| |
| from django.views.decorators.csrf import csrf_protect |
| from django.shortcuts import render |
| |
| @csrf_protect |
| def my_view(request): |
| c = {} |
| # ... |
| return render(request, "a_template.html", c) |
| |
| 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. |
| |
| The error page, however, is not very friendly, so you may want to provide your |
| own view for handling this condition. To do this, simply set the |
| :setting:`CSRF_FAILURE_VIEW` setting. |
| |
| .. _how-csrf-works: |
| |
| 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. |
| |
| 3. For all incoming requests that are not using HTTP GET, HEAD, OPTIONS or |
| TRACE, 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 ignores GET requests (and other requests that are defined as |
| 'safe' by :rfc:`2616`). These requests ought never to have any potentially |
| dangerous side effects , and so a CSRF attack with a GET request ought to be |
| harmless. :rfc:`2616` defines POST, PUT and DELETE as 'unsafe', and all other |
| methods are assumed to be unsafe, for maximum protection. |
| |
| 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. This means that the |
| 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) |
| |
| .. _csrf-limitations: |
| |
| 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. |
| |
| Edge cases |
| ========== |
| |
| Certain views can have unusual requirements that mean they don't fit the normal |
| pattern envisaged here. A number of utilities can be useful in these |
| situations. The scenarios they might be needed in are described in the following |
| section. |
| |
| Utilities |
| --------- |
| |
| .. function:: csrf_exempt(view) |
| |
| This decorator marks a view as being exempt from the protection ensured by |
| the middleware. Example:: |
| |
| from django.views.decorators.csrf import csrf_exempt |
| |
| @csrf_exempt |
| def my_view(request): |
| return HttpResponse('Hello world') |
| |
| .. function:: requires_csrf_token(view) |
| |
| Normally the :ttag:`csrf_token` template tag will not work if |
| ``CsrfViewMiddleware.process_view`` or an equivalent like ``csrf_protect`` |
| has not run. The view decorator ``requires_csrf_token`` can be used to |
| ensure the template tag does work. This decorator works similarly to |
| ``csrf_protect``, but never rejects an incoming request. |
| |
| Example:: |
| |
| from django.views.decorators.csrf import requires_csrf_token |
| from django.shortcuts import render |
| |
| @requires_csrf_token |
| def my_view(request): |
| c = {} |
| # ... |
| return render(request, "a_template.html", c) |
| |
| .. function:: ensure_csrf_cookie(view) |
| |
| .. versionadded:: 1.4 |
| |
| This decorator forces a view to send the CSRF cookie. |
| |
| Scenarios |
| --------- |
| |
| CSRF protection should be disabled for just a few views |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| Most views requires CSRF protection, but a few do not. |
| |
| Solution: rather than disabling the middleware and applying ``csrf_protect`` to |
| all the views that need it, enable the middleware and use |
| :func:`~django.views.decorators.csrf.csrf_exempt`. |
| |
| CsrfViewMiddleware.process_view not used |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| There are cases when ``CsrfViewMiddleware.process_view`` may not have run |
| before your view is run - 404 and 500 handlers, for example - but you still |
| need the CSRF token in a form. |
| |
| Solution: use :func:`~django.views.decorators.csrf.requires_csrf_token` |
| |
| Unprotected view needs the CSRF token |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| There may be some views that are unprotected and have been exempted by |
| ``csrf_exempt``, but still need to include the CSRF token. |
| |
| Solution: use :func:`~django.views.decorators.csrf.csrf_exempt` followed by |
| :func:`~django.views.decorators.csrf.requires_csrf_token`. (i.e. ``requires_csrf_token`` |
| should be the innermost decorator). |
| |
| View needs protection for one path |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| A view needs CRSF protection under one set of conditions only, and mustn't have |
| it for the rest of the time. |
| |
| Solution: use :func:`~django.views.decorators.csrf.csrf_exempt` for the whole |
| view function, and :func:`~django.views.decorators.csrf.csrf_protect` for the |
| path within it that needs protection. Example:: |
| |
| from django.views.decorators.csrf import csrf_exempt, csrf_protect |
| |
| @csrf_exempt |
| def my_view(request): |
| |
| @csrf_protect |
| def protected_path(request): |
| do_something() |
| |
| if some_condition(): |
| return protected_path(request) |
| else: |
| do_something_else() |
| |
| Page uses AJAX without any HTML form |
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| |
| A page makes a POST request via AJAX, and the page does not have an HTML form |
| with a :ttag:`csrf_token` that would cause the required CSRF cookie to be sent. |
| |
| Solution: use :func:`~django.views.decorators.csrf.ensure_csrf_cookie` on the |
| view that sends the page. |
| |
| 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. |
| |
| Settings |
| ======== |
| |
| A number of settings can be used to control Django's CSRF behavior. |
| |
| CSRF_COOKIE_DOMAIN |
| ------------------ |
| |
| .. versionadded:: 1.2 |
| |
| Default: ``None`` |
| |
| The domain to be used when setting the CSRF cookie. This can be useful for |
| easily allowing cross-subdomain requests to be excluded from the normal cross |
| site request forgery protection. It should be set to a string such as |
| ``".lawrence.com"`` to allow a POST request from a form on one subdomain to be |
| accepted by a view served from another subdomain. |
| |
| Please note that, with or without use of this setting, this CSRF protection |
| mechanism is not safe against cross-subdomain attacks -- see `Limitations`_. |
| |
| CSRF_COOKIE_NAME |
| ---------------- |
| |
| .. versionadded:: 1.2 |
| |
| Default: ``'csrftoken'`` |
| |
| The name of the cookie to use for the CSRF authentication token. This can be |
| whatever you want. |
| |
| CSRF_COOKIE_PATH |
| ---------------- |
| |
| .. versionadded:: 1.4 |
| |
| Default: ``'/'`` |
| |
| The path set on the CSRF cookie. This should either match the URL path of your |
| Django installation or be a parent of that path. |
| |
| This is useful if you have multiple Django instances running under the same |
| hostname. They can use different cookie paths, and each instance will only see |
| its own CSRF cookie. |
| |
| CSRF_COOKIE_SECURE |
| ------------------ |
| |
| .. versionadded:: 1.4 |
| |
| Default: ``False`` |
| |
| Whether to use a secure cookie for the CSRF cookie. If this is set to ``True``, |
| the cookie will be marked as "secure," which means browsers may ensure that the |
| cookie is only sent under an HTTPS connection. |
| |
| CSRF_FAILURE_VIEW |
| ----------------- |
| |
| .. versionadded:: 1.2 |
| |
| Default: ``'django.views.csrf.csrf_failure'`` |
| |
| A dotted path to the view function to be used when an incoming request |
| is rejected by the CSRF protection. The function should have this 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. |