Re: Proposal: Modifying the CSRF protection scheme

2013-08-09 Thread Shai Berger
On Friday 09 August 2013 18:08:26 Luke Plant wrote:
> On 03/08/13 23:57, Shai Berger wrote:
> > This would work exactly like it works today, except with signed cookies.
> > That is, the "user specific element" is the cookie. CSRF is about
> > tricking the user into submitting a request designed out of the site --
> > an attacker can't just set (or read) cookies on a user's browser, nor
> > read tokens from the page, under the assumptions we're making about the
> > general setup.
> 
> A signed cookie is not "user specific" in the sense I meant. It is only
> user specific if it cannot be transferred to another user and still
> work. But a signed CSRF cookie, with a matching token, can indeed be
> transferred to another user (unless the signed data includes the session
> or user id, for instance).
> 

The token can, but the cookie cannot (without a much more severe attack). This 
is the foundation that Django's current CSRF protection stands on.

> In this case, signing the cookie only adds protection if the SECRET_KEY
> is changed after the exploit. It doesn't stop the attacker getting and
> using a valid CSRF cookie/token in the first place.
> 

I never argued it did more. And as has been noted, no CSRF protection scheme 
can prevent an attacker with an active XSS or MITM exploit from getting CSRF 
cookies and tokens. Such an attacker can completely control the user session.

The point of the change, to repeat and summarize, is:

1) Make it easier to come back from an exploit
and, not discussed in this sub-thread,
2)  add time-limited tokens
3) Make the scheme look more secure at first glance

Note, that is not "make it look more secure than it is" but make it look more 
secure than it looks now".

Shai.

-- 
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 django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Proposal: Modifying the CSRF protection scheme

2013-08-09 Thread Luke Plant
On 03/08/13 23:57, Shai Berger wrote:

> This would work exactly like it works today, except with signed cookies. That 
> is, the "user specific element" is the cookie. CSRF is about tricking the 
> user 
> into submitting a request designed out of the site -- an attacker can't just 
> set (or read) cookies on a user's browser, nor read tokens from the page, 
> under the assumptions we're making about the general setup.

A signed cookie is not "user specific" in the sense I meant. It is only
user specific if it cannot be transferred to another user and still
work. But a signed CSRF cookie, with a matching token, can indeed be
transferred to another user (unless the signed data includes the session
or user id, for instance).

In this case, signing the cookie only adds protection if the SECRET_KEY
is changed after the exploit. It doesn't stop the attacker getting and
using a valid CSRF cookie/token in the first place.


Luke

-- 
"DO NOT DISTURB.  I'm disturbed enough already."

Luke Plant || http://lukeplant.me.uk/

-- 
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 django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
For more options, visit https://groups.google.com/groups/opt_out.




Re: Proposal: Modifying the CSRF protection scheme

2013-08-07 Thread Shai Berger
Hi,

You can find my work-in-progress at https://github.com/django/django/pull/1454.
It is nowhere near ready yet -- it is still missing some pieces and has
commented-out debug printing, but I'm done for tonight, and I think it is
advanced enough that people may want to take a look and comment.


On Saturday 03 August 2013 19:51:30 Michael Mior wrote:
> In light of BREACH[1] it might be worth looking into having the option of
> adding a one-time pad to the CSRF token as well. Has anyone started
> development on any of the suggestions in this thread yet? If not, it's
> something I'd be interested in exploring.
> 
> [1] 
> http://breachattack.com/resources/BREACH%20-%20SSL,%20gone%20in%2030%20seconds.pdf
> 
 
I did not include anything related to BREACH -- at first I thought that adding
the signature (which is very close to random padding) on both sides of the
secret would help, but apparently that is not very valuable; on the contrary, 
the timestamp gives very predictable context at the end of the secret token.
So the solution will probably involve using some sort of XORed (or otherwise 
added) one-time pad. Thanks to the good work of django.core.signing, 
which I am trying to build upon, I think this will be easy to add (as a new 
kind of signer).

Your comments are welcome; I hope I'm not completely off-base,

Shai.

-- 
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 django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
For more options, visit https://groups.google.com/groups/opt_out.




Re: Proposal: Modifying the CSRF protection scheme

2013-08-03 Thread Shai Berger
Hi,

On Sunday 04 August 2013 01:26:58 Luke Plant wrote:
> On 28/07/13 00:12, Shai Berger wrote:
> > 
> > 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.
> 
> I don't understand how this is supposed to work. For most Django sites,
> it is trivial to get a page from a site and extract a CSRF token and/or
> CSRF cookie value. (The same-origin policy means that you can't do it
> client-side from a different website, but a tiny server-side script can
> do it). An attacker can use this to forge a token or cookie that looks
> like it was signed by the Django site, because it was.
> 
> If SECRET_KEY is changed, the attacker can just get a new signed value.
> 
> The only way this would work is if there is a user specific element that
> stops the attacker from getting a CSRF token that will work on the
> victim. To do this, you have to go back to tying CSRF tokens to the
> session, or something equivalent.
> 
This would work exactly like it works today, except with signed cookies. That 
is, the "user specific element" is the cookie. CSRF is about tricking the user 
into submitting a request designed out of the site -- an attacker can't just 
set (or read) cookies on a user's browser, nor read tokens from the page, 
under the assumptions we're making about the general setup.

Shai.

-- 
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 django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
For more options, visit https://groups.google.com/groups/opt_out.




Re: Proposal: Modifying the CSRF protection scheme

2013-08-03 Thread Luke Plant
On 28/07/13 00:12, Shai Berger 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.

I understand your point, but personally I'm not that impressed by
everything that OWASP does. In general they are good, but some of their
previous recommendations have been way off. In one case, concerning CSRF
tokens in GET parameters, I had a long email exchange with them.
They did eventually (kind of) concede my point, but they didn't bother
to fix anything. Instead they asked me to do it, but it took me about 2
years to actually get a login for their wiki to be able to do that.

> 
> 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.

I don't understand how this is supposed to work. For most Django sites,
it is trivial to get a page from a site and extract a CSRF token and/or
CSRF cookie value. (The same-origin policy means that you can't do it
client-side from a different website, but a tiny server-side script can
do it). An attacker can use this to forge a token or cookie that looks
like it was signed by the Django site, because it was.

If SECRET_KEY is changed, the attacker can just get a new signed value.

The only way this would work is if there is a user specific element that
stops the attacker from getting a CSRF token that will work on the
victim. To do this, you have to go back to tying CSRF tokens to the
session, or something equivalent.

It's for this reason that I'm pretty unenthusiastic about the proposed
changes. I think adding complexity is more likely to confuse us.

Luke


-- 
"Because Your lovingkindness is better than life,
 My lips shall praise You."  (Ps 63:3)

Luke Plant || http://lukeplant.me.uk/

-- 
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 django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
For more options, visit https://groups.google.com/groups/opt_out.




Re: Proposal: Modifying the CSRF protection scheme

2013-08-03 Thread Michael Mior
In light of BREACH[1] it might be worth looking into having the option of 
adding a one-time pad to the CSRF token as well. Has anyone started 
development on any of the suggestions in this thread yet? If not, it's 
something I'd be interested in exploring.

Cheers,
--
Michael Mior
michael.m...@gmail.com

[1] 
http://breachattack.com/resources/BREACH%20-%20SSL,%20gone%20in%2030%20seconds.pdf

Le mardi 30 juillet 2013 13:29:39 UTC-4, Paul McMillan a écrit :
>
> I agree with Jacob on both points. 
>
> +1 from me, especially since neither of these changes should require 
> changes in application code which is already using the interface 
> correctly. 
>
> -Paul 
>
> On Tue, Jul 30, 2013 at 1:22 PM, Jacob Kaplan-Moss 
>  
> wrote: 
> > 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 
> >  
> 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 -- 

Re: Proposal: Modifying the CSRF protection scheme

2013-07-30 Thread Paul McMillan
I agree with Jacob on both points.

+1 from me, especially since neither of these changes should require
changes in application code which is already using the interface
correctly.

-Paul

On Tue, Jul 30, 2013 at 1:22 PM, Jacob Kaplan-Moss  wrote:
> 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  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 

Re: Proposal: Modifying the CSRF protection scheme

2013-07-30 Thread Jacob Kaplan-Moss
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  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]
> 

Re: Proposal: Modifying the CSRF protection scheme

2013-07-29 Thread Shai Berger
Hi

(quotation below edited)

On Monday 29 July 2013 17:59:53 Matthew Lauber wrote:
> On Sat, Jul 27, 2013 at 7:12 PM, Shai Berger  wrote:
> > 
> > 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 I understand (a), it sounds like an excellent scheme, and something that
> would be simple to update behind the scenes without unduly affecting
> application code.  I'm more ambivalent about (b).  Have you or anyone else
> started work on a patch/pull-request for this?
> 
Not that I'm aware of, but (a) is not a new idea, so there may be something 
out there. Either way, I do not intend to force code-changes on any user with 
this.

Shai.

-- 
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 django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
For more options, visit https://groups.google.com/groups/opt_out.




Re: Proposal: Modifying the CSRF protection scheme

2013-07-29 Thread Matthew Lauber
As I understand (a), it sounds like an excellent scheme, and something that
would be simple to update behind the scenes without unduly affecting
application code.  I'm more ambivalent about (b).  Have you or anyone else
started work on a patch/pull-request for this?



On Sat, Jul 27, 2013 at 7:12 PM, Shai Berger  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 

Proposal: Modifying the CSRF protection scheme

2013-07-27 Thread Shai Berger
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 django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.
For more options, visit https://groups.google.com/groups/opt_out.