Yes, indeed -- we should do this, and do it quick. CSRFMiddleware is a
hack; this would be quite a bit nicer.
I've not thought this through nearly as much as you or Brian obvious
have, so I'll leave you two to discuss, however, I have one thought...
On Mon, Sep 22, 2008 at 4:16 PM, Simon Willison <si...@simonwillison.net> wrote:
> You've reminded me of another problem with SafeForm: how does it
> interact with ModelForms? Is there a SafeModelForm as well? What about
> FormSets?
This makes me think -- is it possible that CSRF protection at the form
level is too low? Perhaps it's something that needs to be happening
at, say, the view level? Some sort of decorator, and/or a tag to spit
out the CSRF token in the template...
Just a thought, and now I'll butt out and let you two actually get
some work done.
Jacob
Timestamp and REMOTE_ADDR wouldn't make a proper token unless we also
On Sep 23, 12:13 pm, oggy <ognjen.ma...@gmail.com> wrote:
> Could we just include something like a signed salt+timestamp
> +REMOTE_ADDR in a hidden field? It's not exactly bulletproof because
> of the possibility of a same-IP-CSRF (affecting people behind
> proxies), but it's dead simple and doesn't require a lot of code
> change: Form -> SafeForm + request as the first parameter to __init__.
> Heck, I'd even trust sed to do it for me ;).
included the timestamp and REMOTE_ADDR as hidden fields -- the server
needs to be able to *regenerate* the token when the form is submitted
in order to validate the POSTed token.
There is another option, a template tag. I would implement it as a
middleware and a template tag. Template tag csrf_protect, will require
CSRFMiddleware and django.core.context_processors.request, will add a
input file containing something derived from {{ request }} and
middleware will check and raise HttpForbidden. Its so ugly that it
does not deserve a form validation error in my opinion. This will
require least amount of changes in existing sites.
--
Amit Upadhyay
Vakow! www.vakow.com
+91-9820-295-512
My first reaction is that inheritance is not appropriate for this. I
would add something to a Form Meta nested class like 'safe_form =
False' with True becoming the default. True being the default has
potential to break older apps, but a setting could change the default,
and security is probably important enough to add the small
inconvenience. Forms would then need to be rendered with the hidden
__csfr_token input where the value is provided by middleware. Then
you need some setting that says use a session or separate signed
cookie to verify the token from the form submit. The default
behaviour could be to use session when available and fall back on
cookie otherwise (which can be overriden with a setting).
A form init could become something like MyForm(request.POST,
safe_token=csfr.get_token(request))
-Dave
> CSRF[1] is one of the most common web application vulnerabilities, but
> continues to have very poor awareness in the developer community.
> Django ships with CSRF protection in the form of middleware, but it's
> off by default. I'm willing to bet most people don't turn it on.
>
> I don't believe middleware is the right way to approach this. It's too
> "magic" - it involves code that parses and re-writes your HTML as the
> response is being returned. It also means CSRF failures can't be
> gracefully handled - the middleware can throw up a big ugly error
> page, but ideally a CSRF failure would be treated the same way as a
> regular form validation error.
>
> I propose django.forms should include a SafeForm class, which is a
> subclass of Form that includes built-in protection against CSRF. I
> imagine the interface looking something like this:
I carefully prepared a reply to this, only to forget to transfer it to
my memory stick for sending (I have just moved house and I'm without
internet connection to my own computer...). Anyway, here is a shortened
version, hope it makes some kind of sense as it was written hurriedly.
I'm unlikely to be able to reply to any responses to this, for reasons
mentioned above.
I agree that the CsrfMiddleware is ugly, but before replacing it, here
are the things about it that I do like:
- It Just Works (after you turn it on).
- The only ugly bit (which is also the 'fragile' bit) is the post
processing HTML munging, and if this fails, you are secure by default.
- You don't have to remember to do *anything* for it to work, you just
turn it on once. This is a big deal -- this is why we have SQL escaping
in the ORM, and auto-escaping in the templates. If you leave something
to human error, humans will make an error.
- You don't have security related boilerplate code messing up every
view function. This means all the ugliness of having to deal with the
real world of CSRF etc has been confined to one ugly middleware.
- It works for non-Django forms, which I do have sometimes e.g. forms
with a dynamic number of controls, like tables with a checkbox in each
row for manipulating large numbers of objects. I have several instances
of this in my code already, I'm glad I don't have to re-implement CSRF
protection for these. It also Just Works for AJAX (you may have to do
extra work to get hold of the token client side, and of course you need
to use POST appropriately in your AJAX).
- If we moved to a SafeForm, at least the SafeForm code thus far
proposed, it would be more work to be CSRF safe than non-safe, and all
the example code for Django froms on tutorials acrosss the internet
would therefore be non-safe, just like all the example PHP code across
the web is vulnerable to all kind of hacks.
- There are ways of making the existing implementation nicer (e.g.
redirect to a view which handles the error more gracefully, with a link
(via REFERER header or something) to the original page, or something
like that), and we could turn it on by default in default settings -
SafeForm probably couldn't do that.
I'm not saying don't replace it, but let's make sure the cure is better
than the illness.
Regards,
Luke