Hey Shai -

I have no objections to this change. I think it's got a slight whiff of
security theatre, in that it *looks* like it adds more protection than it
*actually* does. However, I, too, have spent a ton of time talking auditors
down from "OMG Django is vulnerable to CSRF!" and I'd like to do less of
that. I like that rotating SECRET_KEY invalidates CSRF tokens.

Time-limiting is a nice feature too, actually. Again the perceived security
is higher than the actual added security, but the general principle of
giving people more control is a good one. I'm sure there's some audit
checklist out there that has "CSRF tokens must not be valid for longer than
X hours" or something on it, and helping our users tick those boxes isn't
such a bad thing.

So yeah, lukewarm praise from me at best, but since there's at least a bit
of real improvement here I see no reason this shouldn't go in. +1 from me.

Jacob


On Sat, Jul 27, 2013 at 6:12 PM, Shai Berger <[email protected]> wrote:

> Hi everybody,
>
> TL;DR: A simple change can make Django's CSRF protection a little better;
> an
> additional, slightly less simple one, can also make it look better.
>
> Django's CSRF protection scheme is a bit unusual; unlike most such
> schemes, it
> does not rely on a value stored in the server that needs to be matched by a
> submitted token and is replaced with every submission, but rather on a
> constant value stored in a cookie. This generally works (for details of how
> and under what conditions exactly, see [1]), but has two minor problems:
>
> 1) It is unusual, and in particular diverges from what OWASP[2]
> recommends[3];
> as a result, security analysts often think it is not secure. They have been
> proven wrong in all cases members of core are aware of, but proving it
> again
> and again is a nuisance, and there may be bad PR related to this.
>
> 2) It carries a "second-order" vulnerability: If your site has been
> compromised (XSS, Man-in-the-middle, or server compromise) then you become
> persistently vulnerable to CSRF. All of these vulnerabilities are way worse
> than CSRF and render all CSRF protection schemes worthless while they last;
> the point is *not* that they allow CSRF, but rather that they allow CSRF
> to be
> performed after the main hole has been plugged. This is because the
> attacker
> can use the main vulnerability to "steal", or even set, csrftoken cookie
> values, which they can then use later. After a successful attack of this
> magnitude, you need to reset the csrftoken cookies of all users, and this
> is
> neither obvious nor straightforward to do.
>
> Django's unique scheme does have two advantages over the more common
> solutions, which we would like to keep:
>
> 1) It is not tied to sessions, users, or site-stored per-user data,
> allowing
> CSRF protection to a wider range of users
>
> 2) It avoids the problem of having only one "current" token, which causes
> the
> submission of one form to invalidate forms open in other browser tabs.
>
> To improve on both problem issues, while keeping the advantages, I suggest
> the
> following modifications:
>
> a) Use a signed cookie for csrftoken -- using Django's existing signing
> facility[4], this means signing the cookie with the SECRET_KEY from the
> settings; so that an attacker cannot set arbitrary cookies, and changing
> the
> SECRET_KEY after a compromise immeiately invalidates csrftoken cookies.
>
> b) Optionally allowing time-limited CSRF tokens. Such tokens will be
> generated
> by adding a parameter of maximum age to the csrftoken tag, and by marking
> view
> methods (specifically with a decorator, or globally with a setting) as
> requiring timed tokens. When this is used, the posted token value will
> need to
> be different from the cookie value -- to keep advantage 2, the cookie will
> still be constant, and expiry time will only be present in the submitted
> token[5]. This method breaks the current way we do CSRF-protected AJAX, so
> it
> will likely stay optional (and opt-in).
>
> As you may guess, signing the cookie adds an actual iota of security.
> Adding
> expiry adds very little -- if an attacker has access to the cookie, they
> can
> usually just ask the site to generate valid tokens for them, so getting any
> real protection will require annoyingly short expiry times. But the fact
> that
> an attacker needs this extra step makes it a tiny bit harder for them and
> makes their actions a tiny bit more detectable; and having a constantly-
> changing CSRF token may make the whole thing look a little better to naive
> analysts.
>
> I had some help and guidance in drafting this proposal -- you can credit
> Donald Stufft, mostly, for any egregious blunder I didn't make. I am still
> responsible for the ones I did make.
>
> Your comments are welcome,
>
>         Shai.
>
>
> [1]  https://docs.djangoproject.com/en/dev/ref/contrib/csrf/ -- in
> particular,
> "how it works" and "limitations"
>
> [2] https://www.owasp.org
>
> [3]
> https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Prevention_Cheat_Sheet
>
> [4] https://docs.djangoproject.com/en/dev/topics/signing/
>
> [5] django.core.signing.TimestampSigner signs content with the time of the
> signature, and then takes a max_age in its unsign() method; the suggested
> method would go the other way around, timestamping the token with the time
> of
> expiry, to allow checking without using data stored on the server (and to
> allow different forms to use different max-age values).
>
> --
> You received this message because you are subscribed to the Google Groups
> "Django developers" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To post to this group, send email to [email protected].
> Visit this group at http://groups.google.com/group/django-developers.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/django-developers.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to