I'm passing in a csrf_token for every post and xhr request and want to validate the token against the session csrf token. If they don't match, I throw a 401.
I've used the NewResponse subscriber in pyramid to inspect the request and validate the csrf token in the request params against the token in the session. The validation works but it still calls the view so it def does not work as it should.
Any suggestions on the proper way to do this?
@subscriber(NewResponse)
def new_response(event):
"""Check the csrf_token if the user is authenticated and the
request is a post or xhr req.
"""
request = event.request
response = event.response
user = getattr(request, 'user', None)
# For now all xhr request are csrf protected.
if (user and user.is_authenticated()) and \
(request.method == "POST" or request.is_xhr) and \
(not request.params.get('csrf_token') or \
request.params.get('csrf_token') != unicode(request.session.get_csrf_token())):
response.status = '401 Unauthorized'
response.app_iter = []
The NewResponse
subscriber is called after your view is invoked.
You want to be using an event that is invoked earlier, for example NewRequest
or ContextFound
. In Pyramid 1.0, you'll need to use ContextFound
to properly handle things because you cannot raise exceptions in NewRequest
events (this is fixed in 1.1).
The way to do this with a ContextFound
event is to register an exception view for HTTPException objects like this:
config.add_view(lambda ctx, req: ctx, 'pyramid.httpexceptions.HTTPException')
Basically this will return the exception as the response object when you raise it, which is perfectly valid for HTTPException objects which are valid Pyramid Response
objects.
You can then register your event and deal with the CSRF validation:
@subscriber(ContextFound)
def csrf_validation_event(event):
request = event.request
user = getattr(request, 'user', None)
csrf = request.params.get('csrf_token')
if (request.method == 'POST' or request.is_xhr) and \
(user and user.is_authenticated()) and \
(csrf != unicode(request.session.get_csrf_token())):
raise HTTPUnauthorized
Pyramid contains its own CSRF validation, which is probably a better choice.
Given your session stored CSRF tokens, this would result in the following configuration:
from pyramid.csrf import SessionCSRFStoragePolicy
def includeme(config):
# ...
config.set_csrf_storage_policy(SessionCSRFStoragePolicy())
config.set_default_csrf_options(require_csrf=True)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With