Re: JSecurity and CSRF

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Re: JSecurity and CSRF

Les Hazlewood
Administrator
Yep, just read that.  If that is the case, this is an incredibly easy
fix for non-ajax situations:

1.  Create a <jsec:sessionId/> tag that prints out a hidden field:
<input type="hidden" name="JSESSIONID"
value="runtime_session_id_value"/>
2.  Create a Filter implementation that checks the following:

Is there a 'JSESSIONID' parameter in the current request?
- Yes: does it match a previously set Cookie named JSESSIONID?
    - Yes: request is valid, let it through
    - No: potential CSRF attack, show access denied view
- No: no JSESSIOND parameter - let the request through as normal.

3.  Add this to the jsecurity [urls] definition:
/** = antiCsrf

JSecurity doesn't have any AJAX support at all since that varies
dramatically across web environments, so I'm not sure it could do the
AJAX double submit technique.  I do know a JS guru that could help me
find a way if its possible...

Whaddya think?  Does this sound like a viable solution moving forward?

Actually, I wonder if this should logic should be included in the raw
functionality of JSecurity's sessionId acquisition logic when deployed
in web apps - not a user configurable Filter (in case they forget to
configure that filter in the [urls] definition.

P.S.  This needs to be archived, so I'm cc'ing the JSec Dev list...

On Wed, Oct 1, 2008 at 5:17 PM, Graeme Rocher <[hidden email]> wrote:

> Apparently just sending the session cookie in a hidden field and
> comparing the values on the server is a valid fix. At least that is
> how they seem to have implemented it in DWR. See
>
> http://directwebremoting.org/blog/joe/2007/01/01/csrf_attacks_or_how_to_avoid_exposing_your_gmail_contacts.html
>
> Cheers
>
> On Wed, Oct 1, 2008 at 9:01 PM, Les Hazlewood <[hidden email]> wrote:
>> I'll look into the presentation - thanks!
>>
>> But I don't see how a timestamp would matter much.  For example, if
>> site B did the redirect back to site A (using your previous example),
>> that would usually be done within the user's session - often at the
>> same time (or within milliseconds or seconds) of the initial rendering
>> of site A's first page.
>>
>> My other question is when/where would the token be generated?
>> Obviously for it to be verified on a subsequent request, it first
>> needs to be 'bound' somewhere to retrieve for the next request.
>>
>> For example, using <c:out>, it uses response.encodeUrl, which does
>> this work.  Where/how would an end-user do this?  Maybe a sample
>> workflow would help if you could throw one together...
>>
>> Sorry - I'm just trying to lessen my disconnect!
>>
>> Thanks,
>>
>> Les
>>
>> On Wed, Oct 1, 2008 at 3:23 PM, Graeme Rocher <[hidden email]> wrote:
>>> The token needs to be made up of the session id and some time-based
>>> value to avoid replay attacks as you said. So maybe if you take a
>>> random number + session id  + the current time in millis then create a
>>> blowfish encrypted token. Something like
>>>
>>> encrypt("43243-${session.id}-${System.currentTimeMillis()}")
>>>
>>> Then on the server you decrypt the value discard the random number,
>>> read the session id, check that the time value is within the valid
>>> time period (last 15 minutes?) and if not send the request back as not
>>> authorized
>>>
>>> Apparently yahoo use a "crumb" for this. See
>>> http://www.slideshare.net/simon/when-ajax-attacks-web-application-security-fundamentals-presentation/
>>>
>>> Which seems a good presentation on the subject
>>>
>>> Thoughts?
>>>
>>> On Wed, Oct 1, 2008 at 7:16 PM, Les Hazlewood <[hidden email]> wrote:
>>>> Appending the session id to the url poses its own separate problems (session
>>>> fixation attacks, referrer logging attacks, users emailing links to other
>>>> users, etc), and requires that the website programmer (or toolkit) call
>>>> response.encodeUrl(...) (e.g. jstl's <c:out> tag).  I'm assuming this would
>>>> be OK?  I mean, this would happen anyway if cookies were disabled, so
>>>> there's no alternative in that case really.
>>>>
>>>> But the token idea is interesting - how would the token be validated?  If it
>>>> is the session id, that's obviously easy.  But given the above other
>>>> exploits, maybe it should be some other ID?  perhaps a UUID generated just
>>>> for that request?  But then how would the website programmer ensure it is
>>>> used properly?
>>>>
>>>> Just looking for ideas, suggestions...
>>>>
>>>> On Wed, Oct 1, 2008 at 11:58 AM, Graeme Rocher <[hidden email]> wrote:
>>>>>
>>>>> Hi Les,
>>>>>
>>>>> CSRF doesn't rely on the session id or user cookie. Essentially say
>>>>> you're logged into site X using jsecurity. You're a logged in valid
>>>>> user at this point. You then browse to another site B, this site B is
>>>>> evil and has a malicious form that sends the request back to site X to
>>>>> perform some site function (maybe updating data, reseting passwords
>>>>> whatever). Because you are logged in and you have a valid cookie it is
>>>>> allowed by the browser
>>>>>
>>>>> The only way to protect against such an attack is to have some kind of
>>>>> id attached to every request that modifies the data of the server. The
>>>>> id needs to be unique (hence the session id). It would be nice if
>>>>> JSecurity provided built in CSRF capability somehow. Maybe in each
>>>>> form like this you could have a
>>>>>
>>>>> <form action="/modify/some/data">
>>>>>  <jsecurity:token />
>>>>> </form>
>>>>>
>>>>> Then Jsecurity would validate the token. If then evil site B tried to
>>>>> use CSRF to send a request "/modify/some/data" then a 401 would be
>>>>> returned since the token is not sent by evil site B
>>>>>
>>>>> Thoughts?
>>>>>
>>>>> Cheers
>>>>>
>>>>> On Wed, Oct 1, 2008 at 4:45 PM, Les Hazlewood <[hidden email]> wrote:
>>>>> > JSecurity sets the cookie relative to the application path by default,
>>>>> > which
>>>>> > itself is bound by a domain.  I _thought_ cookies from one domain are
>>>>> > not
>>>>> > sent to cookies from another domain by the browser.
>>>>> >
>>>>> > So, in CSRF, if you're visiting a forum on myforum.com and have a
>>>>> > cookie,
>>>>> > JSESSIONID or rememberMe, it is bound to myforum.com.
>>>>> >
>>>>> > If there is a CSRF attack, say, someone posts in that forum, <img
>>>>> > src="http://othersite.com/images/sneakyimage.jpg?blah=blah"/>, I'm
>>>>> > assuming
>>>>> > that lookup results in an HTTP request to a different domain, where the
>>>>> > cookies for only that domain are sent.
>>>>> >
>>>>> > If this is _not_ the case - i.e. the cookies for the domain currently in
>>>>> > the
>>>>> > browser address bar are sent with all HTTP requests for the current
>>>>> > page,
>>>>> > then no, JSecurity doesn't provide any such prevention - it relies on
>>>>> > the
>>>>> > browser to do the right thing and make cookies only accessible to the
>>>>> > domains that set them in the first place.
>>>>> >
>>>>> > I suppose in the above example if the image request results in
>>>>> > JavaScript,
>>>>> > not an actual image, there could be a problem with that script then
>>>>> > reading
>>>>> > the cookies off of the browser locally.
>>>>> >
>>>>> > Do you guys know the current browser behavior?
>>>>> >
>>>>> > I also don't know that an md5 would work - you'd have to do something
>>>>> > like
>>>>> > this:
>>>>> >
>>>>> > Md5Hash(currentDomainName + sessionId) = cookie value
>>>>> >
>>>>> > But, the session id itself needs to be deciphered on the next request to
>>>>> > actually look up the session.  Since MD5 is one way, you can't do this.
>>>>> > You'd have to essentially do a 2 way encryption, like using Blowfish
>>>>> > (which
>>>>> > is what we do for the rememberMe cookie).
>>>>> >
>>>>> > If you guys have any ideas (or you think adding the domain to the cookie
>>>>> > value and then using 2-way encryption is the best way), then lemme know,
>>>>> > and
>>>>> > I'll add it ASAP.
>>>>> >
>>>>> > Cheers,
>>>>> >
>>>>> > Les
>>>>> >
>>>>> >
>>>>> > On Wed, Oct 1, 2008 at 8:06 AM, Peter Ledbrook <[hidden email]> wrote:
>>>>> >>
>>>>> >> > Does JSecurity implement anything for CSRF? For example using an md5
>>>>> >> > of the session id to ensure incoming requests are only from your
>>>>> >> > site?
>>>>> >>
>>>>> >> I don't know, so I've cc'ed Les in. Les, is there anything that you
>>>>> >> know
>>>>> >> of?
>>>>> >>
>>>>> >> Cheers,
>>>>> >>
>>>>> >> Peter
>>>>> >>
>>>>> >> --
>>>>> >> Software Engineer
>>>>> >> G2One, Inc.
>>>>> >> http://www.g2one.com/
>>>>> >
>>>>> >
>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> Graeme Rocher
>>>>> Grails Project Lead
>>>>> G2One, Inc. Chief Technology Officer
>>>>> http://www.g2one.com
>>>>
>>>>
>>>
>>>
>>>
>>> --
>>> Graeme Rocher
>>> Grails Project Lead
>>> G2One, Inc. Chief Technology Officer
>>> http://www.g2one.com
>>>
>>
>
>
>
> --
> Graeme Rocher
> Grails Project Lead
> G2One, Inc. Chief Technology Officer
> http://www.g2one.com
>
Reply | Threaded
Open this post in threaded view
|

Re: JSecurity and CSRF

Graeme Rocher
Hi Les,

Yeh I personally think it would make sense to add the functionality to
the default Filter. There should also be some configuration option so
you can enable/disable the feature.

We can then work on integrating the tag it into the JSecurity plugin
on the Grails side

Cheers

On Wed, Oct 1, 2008 at 11:13 PM, Les Hazlewood <[hidden email]> wrote:

> Yep, just read that.  If that is the case, this is an incredibly easy
> fix for non-ajax situations:
>
> 1.  Create a <jsec:sessionId/> tag that prints out a hidden field:
> <input type="hidden" name="JSESSIONID"
> value="runtime_session_id_value"/>
> 2.  Create a Filter implementation that checks the following:
>
> Is there a 'JSESSIONID' parameter in the current request?
> - Yes: does it match a previously set Cookie named JSESSIONID?
>    - Yes: request is valid, let it through
>    - No: potential CSRF attack, show access denied view
> - No: no JSESSIOND parameter - let the request through as normal.
>
> 3.  Add this to the jsecurity [urls] definition:
> /** = antiCsrf
>
> JSecurity doesn't have any AJAX support at all since that varies
> dramatically across web environments, so I'm not sure it could do the
> AJAX double submit technique.  I do know a JS guru that could help me
> find a way if its possible...
>
> Whaddya think?  Does this sound like a viable solution moving forward?
>
> Actually, I wonder if this should logic should be included in the raw
> functionality of JSecurity's sessionId acquisition logic when deployed
> in web apps - not a user configurable Filter (in case they forget to
> configure that filter in the [urls] definition.
>
> P.S.  This needs to be archived, so I'm cc'ing the JSec Dev list...
>
> On Wed, Oct 1, 2008 at 5:17 PM, Graeme Rocher <[hidden email]> wrote:
>> Apparently just sending the session cookie in a hidden field and
>> comparing the values on the server is a valid fix. At least that is
>> how they seem to have implemented it in DWR. See
>>
>> http://directwebremoting.org/blog/joe/2007/01/01/csrf_attacks_or_how_to_avoid_exposing_your_gmail_contacts.html
>>
>> Cheers
>>
>> On Wed, Oct 1, 2008 at 9:01 PM, Les Hazlewood <[hidden email]> wrote:
>>> I'll look into the presentation - thanks!
>>>
>>> But I don't see how a timestamp would matter much.  For example, if
>>> site B did the redirect back to site A (using your previous example),
>>> that would usually be done within the user's session - often at the
>>> same time (or within milliseconds or seconds) of the initial rendering
>>> of site A's first page.
>>>
>>> My other question is when/where would the token be generated?
>>> Obviously for it to be verified on a subsequent request, it first
>>> needs to be 'bound' somewhere to retrieve for the next request.
>>>
>>> For example, using <c:out>, it uses response.encodeUrl, which does
>>> this work.  Where/how would an end-user do this?  Maybe a sample
>>> workflow would help if you could throw one together...
>>>
>>> Sorry - I'm just trying to lessen my disconnect!
>>>
>>> Thanks,
>>>
>>> Les
>>>
>>> On Wed, Oct 1, 2008 at 3:23 PM, Graeme Rocher <[hidden email]> wrote:
>>>> The token needs to be made up of the session id and some time-based
>>>> value to avoid replay attacks as you said. So maybe if you take a
>>>> random number + session id  + the current time in millis then create a
>>>> blowfish encrypted token. Something like
>>>>
>>>> encrypt("43243-${session.id}-${System.currentTimeMillis()}")
>>>>
>>>> Then on the server you decrypt the value discard the random number,
>>>> read the session id, check that the time value is within the valid
>>>> time period (last 15 minutes?) and if not send the request back as not
>>>> authorized
>>>>
>>>> Apparently yahoo use a "crumb" for this. See
>>>> http://www.slideshare.net/simon/when-ajax-attacks-web-application-security-fundamentals-presentation/
>>>>
>>>> Which seems a good presentation on the subject
>>>>
>>>> Thoughts?
>>>>
>>>> On Wed, Oct 1, 2008 at 7:16 PM, Les Hazlewood <[hidden email]> wrote:
>>>>> Appending the session id to the url poses its own separate problems (session
>>>>> fixation attacks, referrer logging attacks, users emailing links to other
>>>>> users, etc), and requires that the website programmer (or toolkit) call
>>>>> response.encodeUrl(...) (e.g. jstl's <c:out> tag).  I'm assuming this would
>>>>> be OK?  I mean, this would happen anyway if cookies were disabled, so
>>>>> there's no alternative in that case really.
>>>>>
>>>>> But the token idea is interesting - how would the token be validated?  If it
>>>>> is the session id, that's obviously easy.  But given the above other
>>>>> exploits, maybe it should be some other ID?  perhaps a UUID generated just
>>>>> for that request?  But then how would the website programmer ensure it is
>>>>> used properly?
>>>>>
>>>>> Just looking for ideas, suggestions...
>>>>>
>>>>> On Wed, Oct 1, 2008 at 11:58 AM, Graeme Rocher <[hidden email]> wrote:
>>>>>>
>>>>>> Hi Les,
>>>>>>
>>>>>> CSRF doesn't rely on the session id or user cookie. Essentially say
>>>>>> you're logged into site X using jsecurity. You're a logged in valid
>>>>>> user at this point. You then browse to another site B, this site B is
>>>>>> evil and has a malicious form that sends the request back to site X to
>>>>>> perform some site function (maybe updating data, reseting passwords
>>>>>> whatever). Because you are logged in and you have a valid cookie it is
>>>>>> allowed by the browser
>>>>>>
>>>>>> The only way to protect against such an attack is to have some kind of
>>>>>> id attached to every request that modifies the data of the server. The
>>>>>> id needs to be unique (hence the session id). It would be nice if
>>>>>> JSecurity provided built in CSRF capability somehow. Maybe in each
>>>>>> form like this you could have a
>>>>>>
>>>>>> <form action="/modify/some/data">
>>>>>>  <jsecurity:token />
>>>>>> </form>
>>>>>>
>>>>>> Then Jsecurity would validate the token. If then evil site B tried to
>>>>>> use CSRF to send a request "/modify/some/data" then a 401 would be
>>>>>> returned since the token is not sent by evil site B
>>>>>>
>>>>>> Thoughts?
>>>>>>
>>>>>> Cheers
>>>>>>
>>>>>> On Wed, Oct 1, 2008 at 4:45 PM, Les Hazlewood <[hidden email]> wrote:
>>>>>> > JSecurity sets the cookie relative to the application path by default,
>>>>>> > which
>>>>>> > itself is bound by a domain.  I _thought_ cookies from one domain are
>>>>>> > not
>>>>>> > sent to cookies from another domain by the browser.
>>>>>> >
>>>>>> > So, in CSRF, if you're visiting a forum on myforum.com and have a
>>>>>> > cookie,
>>>>>> > JSESSIONID or rememberMe, it is bound to myforum.com.
>>>>>> >
>>>>>> > If there is a CSRF attack, say, someone posts in that forum, <img
>>>>>> > src="http://othersite.com/images/sneakyimage.jpg?blah=blah"/>, I'm
>>>>>> > assuming
>>>>>> > that lookup results in an HTTP request to a different domain, where the
>>>>>> > cookies for only that domain are sent.
>>>>>> >
>>>>>> > If this is _not_ the case - i.e. the cookies for the domain currently in
>>>>>> > the
>>>>>> > browser address bar are sent with all HTTP requests for the current
>>>>>> > page,
>>>>>> > then no, JSecurity doesn't provide any such prevention - it relies on
>>>>>> > the
>>>>>> > browser to do the right thing and make cookies only accessible to the
>>>>>> > domains that set them in the first place.
>>>>>> >
>>>>>> > I suppose in the above example if the image request results in
>>>>>> > JavaScript,
>>>>>> > not an actual image, there could be a problem with that script then
>>>>>> > reading
>>>>>> > the cookies off of the browser locally.
>>>>>> >
>>>>>> > Do you guys know the current browser behavior?
>>>>>> >
>>>>>> > I also don't know that an md5 would work - you'd have to do something
>>>>>> > like
>>>>>> > this:
>>>>>> >
>>>>>> > Md5Hash(currentDomainName + sessionId) = cookie value
>>>>>> >
>>>>>> > But, the session id itself needs to be deciphered on the next request to
>>>>>> > actually look up the session.  Since MD5 is one way, you can't do this.
>>>>>> > You'd have to essentially do a 2 way encryption, like using Blowfish
>>>>>> > (which
>>>>>> > is what we do for the rememberMe cookie).
>>>>>> >
>>>>>> > If you guys have any ideas (or you think adding the domain to the cookie
>>>>>> > value and then using 2-way encryption is the best way), then lemme know,
>>>>>> > and
>>>>>> > I'll add it ASAP.
>>>>>> >
>>>>>> > Cheers,
>>>>>> >
>>>>>> > Les
>>>>>> >
>>>>>> >
>>>>>> > On Wed, Oct 1, 2008 at 8:06 AM, Peter Ledbrook <[hidden email]> wrote:
>>>>>> >>
>>>>>> >> > Does JSecurity implement anything for CSRF? For example using an md5
>>>>>> >> > of the session id to ensure incoming requests are only from your
>>>>>> >> > site?
>>>>>> >>
>>>>>> >> I don't know, so I've cc'ed Les in. Les, is there anything that you
>>>>>> >> know
>>>>>> >> of?
>>>>>> >>
>>>>>> >> Cheers,
>>>>>> >>
>>>>>> >> Peter
>>>>>> >>
>>>>>> >> --
>>>>>> >> Software Engineer
>>>>>> >> G2One, Inc.
>>>>>> >> http://www.g2one.com/
>>>>>> >
>>>>>> >
>>>>>>
>>>>>>
>>>>>>
>>>>>> --
>>>>>> Graeme Rocher
>>>>>> Grails Project Lead
>>>>>> G2One, Inc. Chief Technology Officer
>>>>>> http://www.g2one.com
>>>>>
>>>>>
>>>>
>>>>
>>>>
>>>> --
>>>> Graeme Rocher
>>>> Grails Project Lead
>>>> G2One, Inc. Chief Technology Officer
>>>> http://www.g2one.com
>>>>
>>>
>>
>>
>>
>> --
>> Graeme Rocher
>> Grails Project Lead
>> G2One, Inc. Chief Technology Officer
>> http://www.g2one.com
>>
>



--
Graeme Rocher
Grails Project Lead
G2One, Inc. Chief Technology Officer
http://www.g2one.com
Reply | Threaded
Open this post in threaded view
|

Re: JSecurity and CSRF

pledbrook
In reply to this post by Les Hazlewood
> Yep, just read that.  If that is the case, this is an incredibly easy
> fix for non-ajax situations:
>
> 1.  Create a <jsec:sessionId/> tag that prints out a hidden field:
> <input type="hidden" name="JSESSIONID"
> value="runtime_session_id_value"/>
> 2.  Create a Filter implementation that checks the following:
>
> Is there a 'JSESSIONID' parameter in the current request?
> - Yes: does it match a previously set Cookie named JSESSIONID?
>    - Yes: request is valid, let it through
>    - No: potential CSRF attack, show access denied view
> - No: no JSESSIOND parameter - let the request through as normal.
>
> 3.  Add this to the jsecurity [urls] definition:
> /** = antiCsrf

Has this been implemented? I'm contemplating adding CSRF protection in
the Grails plugin via a <jsec:form/> tag, but if it's in JSecurity
core, I'll go with that.

Cheers,

Peter

PS I won't be adding anything for a month or two yet :) I'm just
reading up on OWASP and CWE for my security chapter.
PPS Graeme/Jeff cover JSecurity in the Definitive Guide to Grails 2nd edition
Reply | Threaded
Open this post in threaded view
|

Re: JSecurity and CSRF

Les Hazlewood-2
Hi Peter,

Nope it hasn't been implemented - it got lost through the cracks because we
didn't create an issue for it.  Could you please add one to Jira?  This
would be useful!  It should be in JSecurity core for sure, and we can make
sure it gets into 1.0

Would you be able to help implement this in conjunction with your Grails
effort?  If not, feel free to outline what you need in the issue so we can
use that to help direct us how to go about the implementation.

Cheers,

Les

On Fri, Jan 23, 2009 at 6:54 AM, Peter Ledbrook <[hidden email]>wrote:

> > Yep, just read that.  If that is the case, this is an incredibly easy
> > fix for non-ajax situations:
> >
> > 1.  Create a <jsec:sessionId/> tag that prints out a hidden field:
> > <input type="hidden" name="JSESSIONID"
> > value="runtime_session_id_value"/>
> > 2.  Create a Filter implementation that checks the following:
> >
> > Is there a 'JSESSIONID' parameter in the current request?
> > - Yes: does it match a previously set Cookie named JSESSIONID?
> >    - Yes: request is valid, let it through
> >    - No: potential CSRF attack, show access denied view
> > - No: no JSESSIOND parameter - let the request through as normal.
> >
> > 3.  Add this to the jsecurity [urls] definition:
> > /** = antiCsrf
>
> Has this been implemented? I'm contemplating adding CSRF protection in
> the Grails plugin via a <jsec:form/> tag, but if it's in JSecurity
> core, I'll go with that.
>
> Cheers,
>
> Peter
>
> PS I won't be adding anything for a month or two yet :) I'm just
> reading up on OWASP and CWE for my security chapter.
> PPS Graeme/Jeff cover JSecurity in the Definitive Guide to Grails 2nd
> edition
>
Reply | Threaded
Open this post in threaded view
|

Re: JSecurity and CSRF

pledbrook
> Nope it hasn't been implemented - it got lost through the cracks because we
> didn't create an issue for it.  Could you please add one to Jira?  This
> would be useful!  It should be in JSecurity core for sure, and we can make
> sure it gets into 1.0

https://issues.apache.org/jira/browse/JSEC-48

> Would you be able to help implement this in conjunction with your Grails
> effort?  If not, feel free to outline what you need in the issue so we can
> use that to help direct us how to go about the implementation.

Not yet, no. The plugin won't be receiving much love for another month
probably. Book is going for final review next week, and then we have a
few more weeks of manic corrections and adding stuff, while also
trying to get the chapters into production. Fun :)

Cheers,

Peter