From d3db878e4beff057400dd780c24f3601a5d31f95 Mon Sep 17 00:00:00 2001 From: Thomas Chaumeny Date: Fri, 31 Oct 2014 23:39:46 +0100 Subject: Moved CSRF docs out of contrib. --- docs/ref/contrib/csrf.txt | 450 ---------------------------------------- docs/ref/contrib/index.txt | 8 - docs/ref/csrf.txt | 449 +++++++++++++++++++++++++++++++++++++++ docs/ref/index.txt | 1 + docs/ref/middleware.txt | 2 +- docs/ref/settings.txt | 4 +- docs/ref/templates/api.txt | 2 +- docs/ref/templates/builtins.txt | 2 +- 8 files changed, 455 insertions(+), 463 deletions(-) delete mode 100644 docs/ref/contrib/csrf.txt create mode 100644 docs/ref/csrf.txt (limited to 'docs/ref') diff --git a/docs/ref/contrib/csrf.txt b/docs/ref/contrib/csrf.txt deleted file mode 100644 index ac6c55a74c..0000000000 --- a/docs/ref/contrib/csrf.txt +++ /dev/null @@ -1,450 +0,0 @@ -===================================== -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 ``
`` element if the form is for an internal URL, e.g.:: - - {% 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. - -.. _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 -`_ 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 using -`settings.crossDomain `_ in jQuery 1.5.1 and -newer: - -.. code-block:: javascript - - function csrfSafeMethod(method) { - // these HTTP methods do not require CSRF protection - return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); - } - $.ajaxSetup({ - beforeSend: function(xhr, settings) { - if (!csrfSafeMethod(settings.type) && !this.crossDomain) { - xhr.setRequestHeader("X-CSRFToken", csrftoken); - } - } - }); - -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 Jinja2 template language, your form could contain the -following: - -.. code-block:: html - -
- -
- -You can use JavaScript similar to the :ref:`AJAX code ` 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 - from django.http import HttpResponse - - @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 ``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 CSRF 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: - -* :setting:`CSRF_COOKIE_AGE` -* :setting:`CSRF_COOKIE_DOMAIN` -* :setting:`CSRF_COOKIE_HTTPONLY` -* :setting:`CSRF_COOKIE_NAME` -* :setting:`CSRF_COOKIE_PATH` -* :setting:`CSRF_COOKIE_SECURE` -* :setting:`CSRF_FAILURE_VIEW` diff --git a/docs/ref/contrib/index.txt b/docs/ref/contrib/index.txt index ebfc2874b4..a4787f8643 100644 --- a/docs/ref/contrib/index.txt +++ b/docs/ref/contrib/index.txt @@ -25,7 +25,6 @@ those packages have. admin/index auth contenttypes - csrf flatpages formtools/index gis/index @@ -63,13 +62,6 @@ Django model is a separate content type. See the :doc:`contenttypes documentation `. -csrf -==== - -A middleware for preventing Cross Site Request Forgeries - -See the :doc:`csrf documentation `. - flatpages ========= diff --git a/docs/ref/csrf.txt b/docs/ref/csrf.txt new file mode 100644 index 0000000000..9e682ec6ae --- /dev/null +++ b/docs/ref/csrf.txt @@ -0,0 +1,449 @@ +===================================== +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 take advantage of CSRF protection in your views, follow these steps: + +1. The CSRF middleware is activated by default in the + :setting:`MIDDLEWARE_CLASSES` setting. If you override that setting, remember + that ``'django.middleware.csrf.CsrfViewMiddleware'`` should come before any + view middleware that assume that CSRF attacks have been dealt with. + + If you disabled it, which is not recommended, you can use + :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 ```` element if the form is for an internal URL, e.g.:: + + {% 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. + +.. _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 +`_ 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 using +`settings.crossDomain `_ in jQuery 1.5.1 and +newer: + +.. code-block:: javascript + + function csrfSafeMethod(method) { + // these HTTP methods do not require CSRF protection + return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); + } + $.ajaxSetup({ + beforeSend: function(xhr, settings) { + if (!csrfSafeMethod(settings.type) && !this.crossDomain) { + xhr.setRequestHeader("X-CSRFToken", csrftoken); + } + } + }); + +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 Jinja2 template language, your form could contain the +following: + +.. code-block:: html + +
+ +
+ +You can use JavaScript similar to the :ref:`AJAX code ` 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 + from django.http import HttpResponse + + @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 ``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 CSRF 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: + +* :setting:`CSRF_COOKIE_AGE` +* :setting:`CSRF_COOKIE_DOMAIN` +* :setting:`CSRF_COOKIE_HTTPONLY` +* :setting:`CSRF_COOKIE_NAME` +* :setting:`CSRF_COOKIE_PATH` +* :setting:`CSRF_COOKIE_SECURE` +* :setting:`CSRF_FAILURE_VIEW` diff --git a/docs/ref/index.txt b/docs/ref/index.txt index 8aef2e9964..b81d8dd7d4 100644 --- a/docs/ref/index.txt +++ b/docs/ref/index.txt @@ -10,6 +10,7 @@ API Reference class-based-views/index clickjacking contrib/index + csrf databases django-admin exceptions diff --git a/docs/ref/middleware.txt b/docs/ref/middleware.txt index eea2d94a84..3ba7d52b9d 100644 --- a/docs/ref/middleware.txt +++ b/docs/ref/middleware.txt @@ -388,7 +388,7 @@ CSRF protection middleware Adds protection against Cross Site Request Forgeries by adding hidden form fields to POST forms and checking requests for the correct value. See the -:doc:`Cross Site Request Forgery protection documentation `. +:doc:`Cross Site Request Forgery protection documentation `. X-Frame-Options middleware -------------------------- diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt index 3fd1c44ce5..90f6e1e147 100644 --- a/docs/ref/settings.txt +++ b/docs/ref/settings.txt @@ -374,7 +374,7 @@ CSRF_COOKIE_NAME Default: ``'csrftoken'`` The name of the cookie to use for the CSRF authentication token. This can be whatever you -want. See :doc:`/ref/contrib/csrf`. +want. See :doc:`/ref/csrf`. .. setting:: CSRF_COOKIE_PATH @@ -415,7 +415,7 @@ is rejected by the CSRF protection. The function should have this signature:: where ``reason`` is a short message (intended for developers or logging, not for end users) indicating the reason the request was rejected. See -:doc:`/ref/contrib/csrf`. +:doc:`/ref/csrf`. .. setting:: DATABASES diff --git a/docs/ref/templates/api.txt b/docs/ref/templates/api.txt index ac6c18fe79..08e001b039 100644 --- a/docs/ref/templates/api.txt +++ b/docs/ref/templates/api.txt @@ -576,7 +576,7 @@ django.core.context_processors.csrf This processor adds a token that is needed by the :ttag:`csrf_token` template tag for protection against :doc:`Cross Site Request Forgeries -`. +`. django.core.context_processors.request ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index e9c2e0c391..fe9127bea5 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -70,7 +70,7 @@ csrf_token ^^^^^^^^^^ This tag is used for CSRF protection, as described in the documentation for -:doc:`Cross Site Request Forgeries `. +:doc:`Cross Site Request Forgeries `. .. templatetag:: cycle -- cgit v1.3