Is there a best practice way to do csrf checking with deform

170 views
Skip to first unread message

Bobby

unread,
Oct 3, 2011, 2:15:30 PM10/3/11
to pylons-discuss
I was thinking of editing the deform.form class and adding the request
as a keyword param. The request would then be used to create a token
attribute in the __init__ method with the rest of the attributes. Then
I would create a custom form template and add a hidden field with the
csrf token.

That takes care of creating the token. Now to checking.

I am thinking this is not a case of validation, but rather a case of
authorization. The options might be subscribing to a NewRequest event
as in this example:
http://stackoverflow.com/questions/6434550/how-do-you-add-csrf-validation-to-pyramid

or possibly using a custom predicate in the view_config.

Using an event listener might be overkill bc it will get called on GET
requests, however adding the custom predicate to every view_config
will get repetitive.

So do you have any suggestions for an elegant way to handle this?
Thank you.

Robert Forkel

unread,
Oct 4, 2011, 1:56:14 AM10/4/11
to pylons-...@googlegroups.com
I do think checking the csrf token is some kind of validation, at
least for some of my apps there's parts of validating a form which
check the authorization of the request and which I couldn't easily
factor out. What I did was adding a "check_precondition" method to my
forms and call this in a overwritten validate method. I do use custom
contexts in these methods, though, which I could also register for
views, so I still have most of the authorization details in one place.
regards
robert

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

Matt Feifarek

unread,
Oct 4, 2011, 4:38:46 PM10/4/11
to pylons-...@googlegroups.com
On Tue, Oct 4, 2011 at 12:56 AM, Robert Forkel <xrot...@googlemail.com> wrote:
I do think checking the csrf token is some kind of validation, at
least for some of my apps there's parts of validating a form which
check the authorization of the request

I'm not sure that this is "best practice" but I found it very convenient to use the events/subscribers to get this check out of my way in my views:

(near my configuration code:)

from pyramid.events import ContextFound, NewRequest
from pyramid.httpexceptions import HTTPForbidden

def check_csrf(request):
    """for any request that has a POST, make sure the CSRF is valid"""
    token = request.session.get_csrf_token()
    if 'csrf' in request.POST and request.POST.get('csrf') == token:
        log.debug("CSRF in POST matches session token")
        return True
    else:
        log.warn("Form POST without CSRF! %s from %s"
                 % (request.url, request.remote_addr))
        return False

def check_request_for_csrf(event):
    if event.request.POST and not check_csrf(event.request):
        raise HTTPForbidden("Token mismatch; bad request")
config.add_subscriber(check_request_for_csrf, NewRequest)

Malthe Borch

unread,
Oct 5, 2011, 9:33:55 AM10/5/11
to pylons-...@googlegroups.com
On 3 October 2011 20:15, Bobby <bobby.ch...@gmail.com> wrote:
> I was thinking of editing the deform.form class and adding the request
> as a keyword param. The request would then be used to create a token
> attribute in the __init__ method with the rest of the attributes. Then
> I would create a custom form template and add a hidden field with the
> csrf token.

Or you could shamelessly add it to your ``formid``, e.g.

Form(formid="deform-%s" % self.request.session.get_crsf_token())

> That takes care of creating the token. Now to checking.

If you're using ``pyramid_deform``, then you could subclass and add:

@reify
def crsf(self):
return self.request.session.get_csrf_token()

@reify
def form_class(self):
return functools.partial(
deform.form.Form,
formid="deform-%s" % self.crsf,
)

def __getattribute__(self, name):
value = object.__getattribute__(self, name)

if name.endswith('_success'):
def crsf_validator(data, crsf=self.crsf, post=self.request.POST):
formid = post.get('__formid__')
token = formid.split('-')[-1]
if token != crsf:
raise HTTPUnauthorized("CRSF validation error")
return value(data)
return crsf_validator
return value

\malthe

Reply all
Reply to author
Forward
0 new messages