Using the ajaxSend event is better than beforeSend, because the beforeSend callback can have only one value, which makes it painful if it is needed by multiple bits of javascript. Thanks to LukeMaurer for report and initial patch. Backport of [15515] from trunk. This is backported to 1.1.X because it really belongs with security patch [15466] git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.1.X@15518 bcc190cf-cafb-0310-a4f2-bffc1f526a37
145 lines
6.1 KiB
Plaintext
145 lines
6.1 KiB
Plaintext
.. _ref-contrib-csrf:
|
|
|
|
=====================================
|
|
Cross Site Request Forgery protection
|
|
=====================================
|
|
|
|
.. module:: django.contrib.csrf
|
|
:synopsis: Protects against Cross Site Request Forgeries
|
|
|
|
The CsrfMiddleware class provides easy-to-use protection against
|
|
`Cross Site Request Forgeries`_. This type of attack occurs when a malicious
|
|
Web site creates a link or form button that is intended to perform some action
|
|
on your Web site, using the credentials of a logged-in user who is tricked
|
|
into clicking on the link in their browser.
|
|
|
|
The first defense against CSRF attacks is to ensure that GET requests
|
|
are side-effect free. POST requests can then be protected by adding this
|
|
middleware into your list of installed middleware.
|
|
|
|
.. _Cross Site Request Forgeries: http://www.squarefree.com/securitytips/web-developers.html#CSRF
|
|
|
|
How to use it
|
|
=============
|
|
|
|
Add the middleware ``'django.contrib.csrf.middleware.CsrfMiddleware'`` to your
|
|
list of middleware classes, :setting:`MIDDLEWARE_CLASSES`. It needs to process
|
|
the response after the SessionMiddleware, so must come before it in the list. It
|
|
also must process the response before things like compression or setting of
|
|
ETags happen to the response, so it must come after GZipMiddleware,
|
|
CommonMiddleware and ConditionalGetMiddleware in the list.
|
|
|
|
The ``CsrfMiddleware`` class is actually composed of two middleware:
|
|
``CsrfViewMiddleware`` which performs the checks on incoming requests,
|
|
and ``CsrfResponseMiddleware`` which performs post-processing of the
|
|
result. This allows the individual components to be used and/or
|
|
replaced instead of using ``CsrfMiddleware``.
|
|
|
|
.. versionchanged:: 1.1
|
|
(previous versions of Django did not provide these two components
|
|
of ``CsrfMiddleware`` as described above)
|
|
|
|
AJAX
|
|
----
|
|
|
|
While the above method can be used with AJAX POST requests, it has some
|
|
inconveniences: you have to remember to get the CSRF token from the HTML
|
|
document and pass it 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
|
|
|
|
$('html').ajaxSend(function(event, xhr, settings) {
|
|
if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
|
|
// Only send the token to relative URLs i.e. locally.
|
|
xhr.setRequestHeader("X-CSRFToken",
|
|
$("#csrfmiddlewaretoken").val());
|
|
}
|
|
});
|
|
|
|
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. This will only work if you remember to include a form on the page,
|
|
so that the input with id 'csrfmiddlewaretoken' will be found.
|
|
|
|
Exceptions
|
|
----------
|
|
|
|
.. versionadded:: 1.1
|
|
|
|
To manually exclude a view function from being handled by the
|
|
CsrfMiddleware, you can use the ``csrf_exempt`` decorator, found in
|
|
the ``django.contrib.csrf.middleware`` module. For example::
|
|
|
|
from django.contrib.csrf.middleware import csrf_exempt
|
|
|
|
def my_view(request):
|
|
return HttpResponse('Hello world')
|
|
my_view = csrf_exempt(my_view)
|
|
|
|
Like the middleware itself, 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.
|
|
|
|
How it works
|
|
============
|
|
|
|
CsrfMiddleware does two things:
|
|
|
|
1. It modifies outgoing requests by adding a hidden form field to all
|
|
'POST' forms, with the name 'csrfmiddlewaretoken' and a value which is
|
|
a hash of the session ID plus a secret. If there is no session ID set,
|
|
this modification of the response isn't done, so there is very little
|
|
performance penalty for those requests that don't have a session.
|
|
(This is done by ``CsrfResponseMiddleware``).
|
|
|
|
2. On all incoming POST requests that have the session cookie set, it
|
|
checks that the 'csrfmiddlewaretoken' is present and correct. If it
|
|
isn't, the user will get a 403 error. (This is done by
|
|
``CsrfViewMiddleware``)
|
|
|
|
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.
|
|
|
|
POST requests that are not accompanied by a session cookie are not protected,
|
|
but since these requests are not authenticated, they will usually be of limited
|
|
risk.
|
|
|
|
The Content-Type is checked 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
|
|
|
|
Limitations
|
|
===========
|
|
|
|
CsrfMiddleware requires Django's session framework to work. If you have
|
|
a custom authentication system that manually sets cookies and the like,
|
|
it won't help you.
|
|
|
|
The middleware only partially protects against 'Login CSRF'. If you have used
|
|
standard Django views for logging in, then you will be protected, due to the way
|
|
they work (the session must be established in the step before actually logging
|
|
in, so the login step itself is protected). If you have used a different way to
|
|
log in, you may be vulnerable to Login CSRF.
|
|
|
|
If 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. It may still be possible
|
|
to use the middleware, provided you can find some way to get the
|
|
CSRF token and ensure that is included when your form is submitted.
|