Как добавить проверку csrf в pyramid?

Я передаю csrf_token для каждого запроса post и xhr и хочу проверить токен против токена csrf сеанса. Если они не совпадают, я бросаю 401.

я использовал подписчика NewResponse в пирамиде, чтобы проверить запрос и проверить токен csrf в параметрах запроса против токена в сеансе. Проверка работает, но она по-прежнему вызывает представление, поэтому def не работает так, как должно.

любые предложения о правильном способе сделать это?

@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 = []

2 ответов


на NewResponse абонент называется после вызывается ваше представление.

вы хотите использовать событие, которое вызывается ранее, например NewRequest или ContextFound. В Pyramid 1.0 вам нужно будет использовать ContextFound правильно обрабатывать вещи, потому что вы не можете создавать исключения в NewRequest события (это зафиксировано в 1.1).

способ сделать это с помощью ContextFound событие для регистрации просмотреть исключением объектов HTTPException как это:

config.add_view(lambda ctx, req: ctx, 'pyramid.httpexceptions.HTTPException')

в основном это вернет исключение в качестве объекта ответа, когда вы его поднимаете, что совершенно справедливо для объектов HTTPException, которые являются допустимыми Pyramid Response объекты.

затем вы можете зарегистрировать свое событие и иметь дело с проверкой CSRF:

@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

пирамида содержит собственная проверка CSRF, что, вероятно, лучший выбор.

учитывая, что в вашем сеансе хранятся токены CSRF, это приведет к следующей конфигурации:

from pyramid.csrf import SessionCSRFStoragePolicy

def includeme(config):
    # ...
    config.set_csrf_storage_policy(SessionCSRFStoragePolicy())
    config.set_default_csrf_options(require_csrf=True)