CSRF

91 views
Skip to first unread message

Aaron Swartz

unread,
Mar 14, 2011, 9:50:38 AM3/14/11
to web. py
thedod added a cookbook page about CSRF to the wiki:
https://github.com/webpy/webpy.github.com/commit/33f34aedc82e040950ca6a92e08fa5bf8f18ede5

My feelings on this are:

1. If code blocks are generally useful, it should be in web.py and not
a cookbook page
2. CSRF is generally useful -- web.py should have CSRF protection
3. The right way to add CSRF to web.py is to write up a spec and run
it by me and a web security expert

web.py's policy on security is generally "secure by default" but it'd
be extremely backwards-incompatible to start requiring CSRF on all
forms. I'm not sure what to do about this. One idea is to have a flag
on web.application that specifies CSRF or not and then have an opt-out
on...I guess web.input? And maybe eventually the flag could be made
default, after enough warning. Another is to just add a new name for
web.input (web.inputs?) and encourage people to use that instead.
That's probably the best idea.

Then there should be two functions built into templetor, one that
returns a hidden input with the token and one that just returns the
token itself.

The main security question is: what's the token? The cookbook page
uses a random number stored in the session. I hate sessions so I of
course I don't like this. I'd prefer some sort of HMAC of the browser
fingerprint, but I don't know if that's secure. This is where the
security expert comes in. I'll ask around about this.

Aaron Swartz

unread,
Mar 14, 2011, 10:01:50 AM3/14/11
to web. py
Actually, what am I saying -- CSRF doesn't make sense without some
sort of session ID. So I guess we default to using the ID in the
session module but allow people to sub in their own if they're not
using that module.

I think we should probably use approach 1 in
https://www.isecpartners.com/files/CSRF_Paper.pdf which gives us an
excuse to change the name of the function. So the API would probably
be something like:

template:
<form method="post" action="/purchase">
$csrf('purchase')
...
</form>

controller:
i = web.inputs('purchase', ...)

Justin Davis

unread,
Mar 14, 2011, 12:46:47 PM3/14/11
to web.py
Why not just set a custom cookie, and use that in the form instead of
a session id? Seems a lot less hacky than browser fingerprints, and
avoids sessions.

On Mar 14, 6:50 am, Aaron Swartz <m...@aaronsw.com> wrote:
> thedod added a cookbook page about CSRF to the wiki:https://github.com/webpy/webpy.github.com/commit/33f34aedc82e040950ca...

Branko Vukelic

unread,
Mar 14, 2011, 1:05:22 PM3/14/11
to we...@googlegroups.com
Afaik, CSRF pretains to users that have been logged-in at some point
in the past, and CSRF prevention is the prevention of privilege
escalation of the logged-in user. So a session id makes sense, because
you already have one.

As for naming, I'd say web.sinput makes a lot more sense (inputs ==
plural of input?).

Instead of templetor function, one might think a function on the form
class would make more sense.

When I wrote a CSRF protection lib for PHP, I used this formula for the token:

base64(
time the token was created +
pseudo-random 32-char salt +
session id +
remote address
)

The time is checked for token timeout set to 300 seconds by default
(for 'pretty secure' sites). The token is stored in the cookie, and
the token's timestamp + salt is stored in the session store. On
subsequent request, the token is checked for timeout and request
rejected if the token has timed out. Browsers that do not send remote
addr also work because the remote addr is null (we only test if
they're different).

Reply all
Reply to author
Forward
0 new messages