On Tue, Sep 7, 2010 at 4:08 AM, Patryk Zawadzki <pat...@pld-linux.org> wrote:
> Hi,
>
> Since CSRF is already being reafactored up-side down in the trunk, I
> thought it might be a good idea to propose a slight modification.

Erm... it is? That's news to me.

Django 1.2 introduced a bunch of very big changes, but those changes
are signed, sealed and delivered. I'm not aware of any major changes
that have already been made, or are planned.

> Currently CSRF either falls through to the resolved view function or
> calls settings.CSRF_FAILURE_VIEW. More than once I've found myself
> wanting something in between. In such cases I'd like the logic flow to
> be able to reach the view, just telling me that CSRF did not validate.
>
> Let's say we add a new attribute to the request, call it "validated"
> and make it default to True for GET and False for everything else. Now
> split the CSRF middleware into two separate pieces of code. One
> middleware that does the validation and sets request.validated to True
> on success. One middleware that checks for (request.method == 'POST'
> and not request.validated) and in such cases returns
> settings.CSRF_FAILURE_VIEW.
>
> "How is that useful?" I hear you ask.
>
> class SecureForm(forms.Form):
>    def __init__(self, *args, **kwargs):
>        self.secure = kwargs.pop('secure', False)
>        return super(SecureForm, self).__init__(*args, **kwargs)
>    def _clean_form(self, *args, **kwargs):
>        if not self.secure:
>            self._errors[NON_FIELD_ERRORS] = self.error_class([
>                'We could not confirm that the request originated from
> your machine. Please resubmit to continue.'
>            ])
>        else:
>            super(SecureForm, self)._clean_form(self, *args, **kwargs)
>
> def MyForm(SecureForm):
>    foo = forms.CharField()
>
> def my_view(request):
>    myform = MyForm(request.POST or None, request.FILES or None,
>            secure=request.validated)
>    if myform.is_valid():
>        # ...
>        pass
>    return direct_to_template(request, 'my.html', {'form': myform})

Hrm. I see what you're doing here.

Firstly, I'm not wild about "secure=request.validated". This looks
like a really simple way for people to say "secure=True" as a way of
"fixing" CSRF support that they can't get to work. The choice of
argument on the attribute isn't optional -- it *must* be
request.validated. So really, it's the request that is the argument
that needs to be passed in. The good news on this point is that a
"request aware form" is something that has been floated in other
discussions recently. I'll be sure to raise it at the DjangoCon
sprints this week as a topic for discussion.

Secondly, IMHO there is a lot of value in the fact that Django forces
the raising of a 403, rather than a 200 with an error message on the
page. This isn't a form input error. It's a catastrophic problem that
should only be observed when the user is actually under attack, or if
cookies aren't available. Displaying a CSRF failure in the same way as
an error for not putting 12 digits in your credit card number strikes
me as the wrong way to visualize the error case. It implies that the
problem can be fixed by user interaction when it can't -- at least,
not by fixing form inputs. In order to give instructions on why
cookies are needed and how to enable them, we need a lot more real
estate... like a CSRF view.

Yours,
Russ Magee %-)

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To post to this group, send email to django-develop...@googlegroups.com.
To unsubscribe from this group, send email to 
django-developers+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-developers?hl=en.

Reply via email to