/docs/ref/contrib/csrf.txt
Plain Text | 472 lines | 370 code | 102 blank | 0 comment | 0 complexity | 1796f55fb4b6e95ed06c06f8b0a51116 MD5 | raw file
Possible License(s): BSD-3-Clause
- =====================================
- 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.