Hi David,

Our CSRF protection is a bit different from that implemented by many
other frameworks. The recommendations we (wearing my OWASP hat) make
as OWASP tend to be conservative and lean towards "safe is better than
sorry." Security and pentest companies tend to make similar
recommendations because they don't have the resources to make
absolutely certain that everything is implemented correctly.

In many frameworks, sessions and CSRF are inextricably linked. You
can't have a form without starting a session. Because Django gets used
in so many different ways, we provide an implementation that allows
you to have CSRF protection without sessions (and without storing any
data persistently server-side). This is useful, for example, if you
have a cluster of machines processing requests behind a load balancer-
you don't have to have keep server-side data in sync across the
cluster.

The way our CSRF tokens work is pretty simple. Each form contains a
CSRF token, which matches the CSRF cookie. Before we process the
protected form, we make sure that the submitted token matches the
cookie. This is a server-side check, but it's not validating against a
stored server-side value. Since a remote attacker should not be able
to read or set arbitrary cookies on your domain, this protects you.

Since we're just matching the cookie with the posted token, the data
is not sensitive (in fact it's completely arbitrary - a cookie of
"zzzz" works just fine), and so the rotation/expiration
recommendations don't make any difference. If an attacker can read or
set arbitrary cookies on your domain, all forms of cookie-based CSRF
protection are broken, full stop.

Generating a new token for each request is problematic from a UI
perspective because it invalidates all previous forms. Most users
would be very unhappy to find that opening a new tab on your site
invalidated the form they'd just spent time filling out in the other
tab, or that a form they accessed via the back button could not be
filled out.

That said, there are a few conditions that need to be met in order to
have Django's CSRF protection work to the fullest extent:

1) Use HTTPS. Use it on your entire site. Use it all the time.
Redirect to the encrypted version for all unencrypted requests. If you
don't do this, no CSRF protection in the world can protect you from a
man-in-the-middle.

2) Use HSTS. Set it for several months. Use "includeSubDomains". This
means that no matter what your users type, and no matter what the
man-in-the-middle does, your users will always access your site
securely if they've been there at least once before.

3) Validate the HOST header in your httpd. Don't allow arbitrary
requests to fall through to Django. Serve your site only for the
appropriate domain. See the most recent security advisory for more
information about this.

If you do these 3 things, you'll be able to take advantage of the
other feature that makes the CSRF protection stronger - strict referer
checking (only enforced over HTTPS). This means that even if a
subdomain can set or modify cookies on your domain, they can't force a
visitor to post to your application, since that request won't come
from your own exact domain.

You should make every effort to avoid allowing subdomains to set or
modify arbitrary cookies, but Django's CSRF protection prevents an
attacking subdomain from causing your users to submit authenticated
posts.

Please feel free to come find me on IRC if you want to chat more about
this - I'm PaulM there and I'm usually in #django-dev. You can also
email me directly if you want to talk in private about your specific
deployment.

So, the tl;dr version: Use HTTPS and HSTS. The recommendations you
received are generally good, but aren't relevant to Django's CSRF
protection.

-Paul

--------
As always, if you think you have found a security issue with Django,
please email secur...@djangoproject.com, rather than posting to the
public lists or the bug tracker.
--------

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-developers@googlegroups.com.
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en.

Reply via email to