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.
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', ...)
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).