I'm thinking about 'championing' this thing, having just done a bit
more work on the existing CsrfMiddleware , and I've done some more
thinking about the different issues. LONG email, sorry, this is quite
== First ==
Simon suggested that the current middleware displays scary messages
when people's sessions' expire, but that doesn't seem to be the case
(normally). The middleware simply checks for a session cookie and
corresponding token, and only if they don't match does it throws a
nasty page back. The token itself does not expire, and even if the
session has, the middleware doesn't know and doesn't care. The
*only* way I have succeeded in getting to the scary "Cross Site
Request Forgery detected" message is like this:
- open a page that returns a POST form (either in a view that
requires authentication or one that doesn't).
- aquire a new session *in a different tab*. This might mean:
1) you had no session when you opened the first page, and you
log in in a different tab.
2) you manually delete the session cookie, and do something
that triggers a new sesssion
3) you are doing something in a different tab, your session
expires by itself and you are given a new one.
- in the first tab, try to submit the form. It fails because the
token in the page disagrees with the new session cookie.
- logging out and logging in in another tab is not enough (unless
this causes a new session to be created).
- waiting for the cookie to expire, or deleting the session from the
database is not enough.
In both these cases, you will be presented by the normal 'your session
has expired' screen for views that require authentication, or you
will simply carry on as normal if the view doesn't require
The above cases that trigger the screen seem to be quite unusual -
I've never seen it myself when actually using a site with the
So what I'm saying is that the 'view protection' part of the
middleware seems to work well enough for the vast majority of cases.
If necessary we could always allow the error page to be customised
via a setting (i.e. allow for a dotted path to a view function), and
we could improve the default implementation to do something sensible,
like display a message and then redirect to the original page after 5
I like the middleware for this part, because it means you are safe by
default, and it works for any POST form -- no special action
Note that the recent changes to this middleware allow you to
selectively turn it off for chosen views using a decorator.
== Second ==
There is the issue of how to insert a CSRF token into the forms. Two
- this takes a request, so it can generate the required field,
removing the need for the 'html munging' part of CsrfMiddleware.
- it could also have a validate method that would remove the need
for the 'view protection' part of CsrfMiddleware
- If the developer is manually specifying each field in their forms
rather than using form.as_table() etc, they will have to edit
- a template tag
- it would require using django.core.context_processors.request
- it would depend on the 'view protection' part of CsrfMiddleware
- it would always require changing the template to insert this tag
- the major advantage is that it can be used with any POST form,
so that no matter how your form works, there is one way to sort
out the CSRF problem - add a template tag (and ensure the
middleware is on).
== Third ==
There is the 'login CSRF' problem.
- simply start a session whenever a login page is accessed if there
is no session already, and then use the normal mechanism above.
- There are some issues with this in terms of implementation 
- bots that hit the login page will generate sessions.
- have a special 'login cookie' - a randomly generated id, not stored
in the database, that is accompanied by a corresponding token.
Requires some custom logic in every login view (you have to
generate the cookie, add it to the response, and also tell the
form/template about the value of the cookie/token).
It may be possible to abstract some of this out into helper
- Add the functionality of the second solution to SafeForm. It would
require SafeForm to be able to set cookies and therefore to access
the response, so the API gets a bit ugly.
== Conclusion ==
At the moment, once you've factored everything in, I think 'view
middleware' + template tag is the way to go, with some more custom
solution for login CSRF. The SafeForm ends up having an unwieldly
API, which means it won't be used or could be used incorrectly, it
will often require changing a template anyway, and it's specific to
Django forms. The template tag solution would basically require a
single line being added to the template for each form (plus some
I also suggest we add CsrfMiddleware or CsrfViewMiddleware to the
default middleware and put a note about it in the release notes.
== Notes ==
- automatic exceptions for AJAX
- manual exceptions possible
- split middleware into two components.
 It will mean:
1) always doing a redirect when you display a login form: you
have to create a new session, send the session cookie with a
HttpRedirectResponse, then in the next request create a form that
has the csrf token in it. Decorators like @staff_member_required
would need changing.
2) creating a new session and returning a form with a csrf token at
the same time. The mechanism that generates the token will need
to be aware that the session ID might not be in
request.COOKIES[SESSION_COOKIE_NAME], but in request.session.??
"Outside of a dog, a book is a man's best friend... inside of a dog,
it's too dark to read."
Luke Plant || http://lukeplant.me.uk/