On Wednesday 01 April 2009 00:10:01 Jacob Kaplan-Moss wrote:
> An even bigger problem would be for users of third-party reusable
> apps: my personal blog is a mere 645 lines of code, but there's
> over 10,000 lines of third-party apps I'm building on top of. If I
> want to upgrade to 1.1 and keep using the admin, I need to wait for
> all of those apps to be upgraded to use CSRF protection.
>
> Now think about an app built on top of Pinax, which itself builds
> on other reusable apps...
Further to my previous emails, I've now updated everything to be as
smooth as possible. I've attached the documentation to this email,
which now includes an 'Upgrading notes' section. In the case of
someone just upgrading without reading those notes or any release
notes, the admin will fail immediately due to checks in
check_dependencies(). If the developer simply follows the two new
instructions it gives, they will end up with a site that is in
essentially the same situation as it was before -- working CSRF
protection for all apps if CsrfMiddleware was installed, working apps
but no CSRF protection if it was missing.
They can then follow the upgrade notes and fix other applications at
their leisure.
I think this addresses all your concerns. I'm struggling to *think* of
ways this could be easier now (apart from doing nothing, of course).
I've not updated all the apps to use 'csrf_response_exempt', but the
admin views are updated (at least in the recommended configuration,
using admin_view()).
Regards,
Luke
--
"The number you have dialled is imaginary. Please rotate your
telephone by 90 degrees and try again."
Luke Plant || http://lukeplant.me.uk/
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Django developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/django-developers?hl=en
-~----------~----~----~----~------~----~------~--~---
.. _ref-contrib-csrf:
=====================================
Cross Site Request Forgery protection
=====================================
.. module:: django.contrib.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 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 these
middleware into your list of installed middleware following the steps below.
.. versionadded:: 1.1
The 'contrib' apps, including the admin, depend on the functionality
described here. Anyone upgrading from earlier versions should read
the `Upgrading notes`_ carefully.
.. _Cross Site Request Forgeries:
http://www.squarefree.com/securitytips/web-developers.html#CSRF
How to use it
=============
.. versionchanged:: 1.1
The template tag functionality (the recommended way to use this) was added
in version 1.1. 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.contrib.csrf.middleware.CsrfViewMiddleware'`` to your list of
middleware classes, :setting:`MIDDLEWARE_CLASSES`. (Currently it can
come anywhere in the list with respect to other middleware included in
Django. It should come before any view middleware that assume that CSRF
attacks have been dealt with.)
2. Add ``'django.contrib.csrf'`` to your :setting:`INSTALLED_APPS`.
3. In any template that uses a POST form, first load the 'csrf' template tag
library::
{% load csrf %}
Then use the ``csrf_token`` tag inside the ``<form>`` element, e.g.::
<form action="" method="POST">{% csrf_token %}
4. In the corresponding view functions, ensure that the
``'django.contrib.csrf.context_processors.csrf'`` is being used. Usually,
this can be done in one of two ways:
1. Using RequestContext:
1. Ensure ``'django.contrib.csrf.context_processors.csrf'`` is present
in your :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting. It is
present by default.
2. Use ``RequestContext`` as the context instance in the relevant
views. If you are using generic views or contrib apps, you are
covered already.
2. Manually import and use the processor to generate the CSRF token and
add it to the template context. e.g.::
from django.contrib.csrf.context_processors import csrf
from django.template import Context
from django.shortcuts import render_to_response
def my_view(request):
c = Context()
c.update(csrf(request))
return render_to_response("a_template.html",
context_instance=c)
5. Ensure that any code in a view which could create a new session executes
**before** any templates containing a ``csrf_token`` tag are
rendered. Note that sessions can be created implicitly simply by setting
a value or accessing the contents. If this is done after the template is
rendered, the CSRF token it contains could be incorrect, and the
following form submission will be rejected.
Legacy method
-------------
In Django 1.0, the template tag did not exist. Instead, a post-processing
middleware that re-wrote POST forms to include the CRSF token was used. If you
are upgrading a site from version 1.0 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.contrib.csrf.middleware.CsrfResponseMiddleware'`` to your
:setting:`MIDDLEWARE_CLASSES` setting.
``CsrfResponseMiddleware`` 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.
Use of the ``CsrfResponseMiddleware`` is not recommended, but it can be used as
an interim measure until applications have been updated to use the ``{%
crsf_token %}`` tag.
Django 1.0 provided a single ``CsrfMiddleware`` class. This is also still
available for backwards compatibility. It combines the functions of the two new
middleware.
Upgrading notes
---------------
When upgrading to version 1.1 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.
If you are using any of the contrib apps (such as the admin), there are some
required steps for these applications to continue working. First, the CSRF
application must be added to :setting:`INSTALLED_APPS` (See `How to use it`_
above, step 2). Second, the :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting must
be updated (step 4.1.1 above).
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``.
If you do not have any of the the middleware in your
:setting:`MIDDLEWARE_CLASSES`,
you will have a working installation but without any CSRF protection (just as
you had before). It is recommended to install ``CsrfViewMiddleware`` and
``CsrfResponseMiddleware``, but if you are not interested in having any CSRF
protection, you can simply stop here.
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 3-5. This can be done as soon as is
practical. Any applications that are updated will now require Django 1.1 or
later, since they will use the CSRF template tag library which was not available
in earlier versions.
Finally, once all applications are upgraded, the ``CsrfResponseMiddleware`` can
be removed.
While in the process of upgrading, the ``csrf_response_exempt`` decorator,
described in `Exceptions`_, may be useful. The post-processing middleware
imposes a performance hit, and any views that have been upgraded to use the new
template tag method no longer need it. Using this decorator will allow you to
avoid this performance hit.
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.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, 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.)
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.
How it works
============
The CSRF protection requires two things:
1. A hidden form field with the name 'csrfmiddlewaretoken' must be added to all
outgoing POST forms. The value of this field 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 part is done by the template tag (and with the legacy method, it is done
by ``CsrfResponseMiddleware``).
2. On all incoming POST requests that have the session cookie set, the
'csrfmiddlewaretoken' must be present and correct. If it isn't, the user will
get a 403 error.
This check 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 they do not need to be protected, since the 'attacking' Web site could make
these kind of requests anyway.
The Content-Type is checked before modifying the response, and only pages that
are served as 'text/html' or 'application/xml+xhtml' are modified.
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.)
.. _9.1.1 Safe Methods, HTTP 1.1, RFC 2616:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
Limitations
===========
These middleware require 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.
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. 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.