mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Thanks to skyl for the report. git-svn-id: http://code.djangoproject.com/svn/django/trunk@12086 bcc190cf-cafb-0310-a4f2-bffc1f526a37
		
			
				
	
	
		
			427 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			427 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| .. _ref-contrib-csrf:
 | |
| 
 | |
| =====================================
 | |
| 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.
 | |
| 
 | |
| 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_exempt
 | |
| django.contrib.csrf.middleware.csrf_view_exempt         django.views.decorators.csrf_view_exempt
 | |
| django.contrib.csrf.middleware.csrf_response_exempt     django.views.decorators.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
 | |
| ----------
 | |
| 
 | |
| .. versionadded:: 1.1
 | |
| 
 | |
| 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.
 | |
| 
 | |
| You don't have to worry about doing this for most AJAX views. Any request sent
 | |
| with "X-Requested-With: XMLHttpRequest" is automatically exempt. (See the `How
 | |
| it works`_ section.)
 | |
| 
 | |
| 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.
 | |
| 
 | |
| AJAX
 | |
| ----
 | |
| 
 | |
| The middleware tries to be smart about requests that come in via AJAX. Most
 | |
| modern JavaScript toolkits send an "X-Requested-With: XMLHttpRequest" HTTP
 | |
| header; these requests are detected and automatically *not* handled by this
 | |
| middleware.  We can do this safely because, in the context of a browser, the
 | |
| header can only be added by using ``XMLHttpRequest``, and browsers already
 | |
| implement a same-domain policy for ``XMLHttpRequest``.
 | |
| 
 | |
| For the more recent browsers that relax this same-domain policy, custom headers
 | |
| like "X-Requested-With" are only allowed after the browser has done a
 | |
| 'preflight' check to the server to see if the cross-domain request is allowed,
 | |
| using a strictly 'opt in' mechanism, so the exception for AJAX is still safe—if
 | |
| the developer has specifically opted in to allowing cross-site AJAX POST
 | |
| requests on a specific URL, they obviously don't want the middleware to disallow
 | |
| exactly that.
 | |
| 
 | |
| .. _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.  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.
 | |
| 
 | |
| 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.
 |