8

我为每个帖子和 xhr 请求传递一个 csrf_token,并希望根据会话 csrf 令牌验证令牌。如果它们不匹配,我会抛出 401。

我已经使用金字塔中的 NewResponse 订阅者来检查请求并根据会话中的令牌验证请求参数中的 csrf 令牌。验证有效,但它仍然调用视图,因此它无法正常工作。

关于正确方法的任何建议?

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

2 回答 2

9

在调用您的视图NewResponse调用订阅者。

您想使用之前调用的事件,例如NewRequestContextFound。在 Pyramid 1.0 中,您需要使用ContextFound来正确处理事情,因为您不能在NewRequest事件中引发异常(这在 1.1 中已修复)。

使用事件执行此操作的方法ContextFound是为 HTTPException 对象注册一个异常视图,如下所示:

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

基本上,这将在引发异常时将异常作为响应对象返回,这对于作为有效 PyramidResponse对象的 HTTPException 对象完全有效。

然后,您可以注册您的事件并处理 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
于 2011-06-22T15:59:19.207 回答
1

Pyramid 包含自己的 CSRF 验证,这可能是一个更好的选择。

鉴于您的会话存储了 CSRF 令牌,这将导致以下配置:

from pyramid.csrf import SessionCSRFStoragePolicy

def includeme(config):
    # ...
    config.set_csrf_storage_policy(SessionCSRFStoragePolicy())
    config.set_default_csrf_options(require_csrf=True)
于 2018-08-16T14:16:06.533 回答