mirror of
https://github.com/django/django.git
synced 2025-10-24 14:16:09 +00:00
[soc2009/multidb] Merged up to trunk r11756.
git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/multidb@11758 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
@@ -770,7 +770,7 @@ documented in :ref:`topics-http-urls`::
|
||||
However, the ``self.my_view`` function registered above suffers from two
|
||||
problems:
|
||||
|
||||
* It will *not* perform and permission checks, so it will be accessible to
|
||||
* It will *not* perform any permission checks, so it will be accessible to
|
||||
the general public.
|
||||
* It will *not* provide any header details to prevent caching. This means if
|
||||
the page retrieves data from the database, and caching middleware is
|
||||
@@ -1048,16 +1048,70 @@ automatically::
|
||||
FriendshipInline,
|
||||
]
|
||||
|
||||
Working with Many-to-Many Models
|
||||
--------------------------------
|
||||
|
||||
.. versionadded:: 1.2
|
||||
|
||||
By default, admin widgets for many-to-many relations will be displayed
|
||||
on whichever model contains the actual reference to the ``ManyToManyField``.
|
||||
Depending on your ``ModelAdmin`` definition, each many-to-many field in your
|
||||
model will be represented by a standard HTML ``<select multiple>``, a
|
||||
horizontal or vertical filter, or a ``raw_id_admin`` widget. However, it is
|
||||
also possible to to replace these widgets with inlines.
|
||||
|
||||
Suppose we have the following models::
|
||||
|
||||
class Person(models.Model):
|
||||
name = models.CharField(max_length=128)
|
||||
|
||||
class Group(models.Model):
|
||||
name = models.CharField(max_length=128)
|
||||
members = models.ManyToManyField(Person, related_name='groups')
|
||||
|
||||
If you want to display many-to-many relations using an inline, you can do
|
||||
so by defining an ``InlineModelAdmin`` object for the relationship::
|
||||
|
||||
class MembershipInline(admin.TabularInline):
|
||||
model = Group.members.through
|
||||
|
||||
class PersonAdmin(admin.ModelAdmin):
|
||||
inlines = [
|
||||
MembershipInline,
|
||||
]
|
||||
|
||||
class GroupAdmin(admin.ModelAdmin):
|
||||
inlines = [
|
||||
MembershipInline,
|
||||
]
|
||||
exclude = ('members',)
|
||||
|
||||
There are two features worth noting in this example.
|
||||
|
||||
Firstly - the ``MembershipInline`` class references ``Group.members.through``.
|
||||
The ``through`` attribute is a reference to the model that manages the
|
||||
many-to-many relation. This model is automatically created by Django when you
|
||||
define a many-to-many field.
|
||||
|
||||
Secondly, the ``GroupAdmin`` must manually exclude the ``members`` field.
|
||||
Django displays an admin widget for a many-to-many field on the model that
|
||||
defines the relation (in this case, ``Group``). If you want to use an inline
|
||||
model to represent the many-to-many relationship, you must tell Django's admin
|
||||
to *not* display this widget - otherwise you will end up with two widgets on
|
||||
your admin page for managing the relation.
|
||||
|
||||
In all other respects, the ``InlineModelAdmin`` is exactly the same as any
|
||||
other. You can customize the appearance using any of the normal
|
||||
``InlineModelAdmin`` properties.
|
||||
|
||||
Working with Many-to-Many Intermediary Models
|
||||
----------------------------------------------
|
||||
|
||||
By default, admin widgets for many-to-many relations will be displayed inline
|
||||
on whichever model contains the actual reference to the ``ManyToManyField``.
|
||||
However, when you specify an intermediary model using the ``through``
|
||||
argument to a ``ManyToManyField``, the admin will not display a widget by
|
||||
default. This is because each instance of that intermediary model requires
|
||||
more information than could be displayed in a single widget, and the layout
|
||||
required for multiple widgets will vary depending on the intermediate model.
|
||||
When you specify an intermediary model using the ``through`` argument to a
|
||||
``ManyToManyField``, the admin will not display a widget by default. This is
|
||||
because each instance of that intermediary model requires more information
|
||||
than could be displayed in a single widget, and the layout required for
|
||||
multiple widgets will vary depending on the intermediate model.
|
||||
|
||||
However, we still want to be able to edit that information inline. Fortunately,
|
||||
this is easy to do with inline admin models. Suppose we have the following
|
||||
|
||||
@@ -216,6 +216,13 @@ should know about:
|
||||
it with a warning field; if you use the comment form with a custom
|
||||
template you should be sure to do the same.
|
||||
|
||||
The comments app also depends on the more general :ref:`Cross Site Request
|
||||
Forgery protection < ref-contrib-csrf>` that comes with Django. As described in
|
||||
the documentation, it is best to use ``CsrfViewMiddleware``. However, if you
|
||||
are not using that, you will need to use the ``csrf_protect`` decorator on any
|
||||
views that include the comment form, in order for those views to be able to
|
||||
output the CSRF token and cookie.
|
||||
|
||||
.. _honeypot: http://en.wikipedia.org/wiki/Honeypot_(computing)
|
||||
|
||||
More information
|
||||
|
||||
@@ -4,121 +4,421 @@
|
||||
Cross Site Request Forgery protection
|
||||
=====================================
|
||||
|
||||
.. module:: django.contrib.csrf
|
||||
.. module:: django.middleware.csrf
|
||||
:synopsis: Protects against Cross Site Request Forgeries
|
||||
|
||||
The CsrfMiddleware class provides easy-to-use protection against
|
||||
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 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.
|
||||
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 adding this
|
||||
middleware into your list of installed middleware.
|
||||
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
|
||||
=============
|
||||
|
||||
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
|
||||
happen to the response, so it must come after GZipMiddleware in the
|
||||
list.
|
||||
.. 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`_.
|
||||
|
||||
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``.
|
||||
To enable CSRF protection for your views, follow these steps:
|
||||
|
||||
.. versionchanged:: 1.1
|
||||
(previous versions of Django did not provide these two components
|
||||
of ``CsrfMiddleware`` as described above)
|
||||
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 ``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 ``{% 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.
|
||||
|
||||
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 ``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 the
|
||||
CsrfMiddleware, you can use the ``csrf_exempt`` decorator, found in
|
||||
the ``django.contrib.csrf.middleware`` module. For example::
|
||||
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.contrib.csrf.middleware import csrf_exempt
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
@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.
|
||||
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 next section.)
|
||||
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
|
||||
============
|
||||
|
||||
CsrfMiddleware does two things:
|
||||
The CSRF protection is based on the following 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``).
|
||||
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.
|
||||
|
||||
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 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).
|
||||
|
||||
This ensures that only forms that have originated from your Web site
|
||||
can be used to POST data back.
|
||||
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.
|
||||
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 they do not need to be protected, since the 'attacking' Web site
|
||||
could make these kind of requests anyway.
|
||||
``CsrfResponseMiddleware`` checks the Content-Type before modifying the
|
||||
response, and only pages that are served as 'text/html' or
|
||||
'application/xml+xhtml' are modified.
|
||||
|
||||
The Content-Type is checked 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. Many
|
||||
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``. (Note that this is not secure if you
|
||||
don't trust content within the same domain or subdomains.)
|
||||
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 ``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
|
||||
===========
|
||||
|
||||
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.
|
||||
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 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.
|
||||
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.
|
||||
|
||||
@@ -177,7 +177,7 @@ Here's a full example template:
|
||||
|
||||
{% block content %}
|
||||
<p>Step {{ step }} of {{ step_count }}</p>
|
||||
<form action="." method="post">
|
||||
<form action="." method="post">{% csrf_token %}
|
||||
<table>
|
||||
{{ form }}
|
||||
</table>
|
||||
|
||||
Reference in New Issue
Block a user