123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470 |
- =====================================
- 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`_) 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
- .. _9.1.1 Safe Methods, HTTP 1.1, RFC 2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
- .. _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
- and 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. 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'));
- }
- });
- 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 above code could be simplified by using the `jQuery cookie plugin
- <http://plugins.jquery.com/project/Cookie>`_ to replace ``getCookie``, and
- `settings.crossDomain <http://api.jquery.com/jQuery.ajax>`_ in jQuery 1.5 and
- later to replace ``sameOrigin``.
- In addition, if the CSRF cookie has not been sent to the client by use of
- :ttag:`csrf_token`, you may need to ensure the client receives the cookie by
- using :func:`~django.views.decorators.csrf.ensure_csrf_cookie`.
- 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. In this case, on any views
- that will require a CSRF token to be inserted you should use the
- :func:`django.views.decorators.vary.vary_on_cookie` decorator first::
- from django.views.decorators.cache import cache_page
- from django.views.decorators.vary import vary_on_cookie
- @cache_page(60 * 15)
- @vary_on_cookie
- 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)
- 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 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 exluded 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 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.
|