【问题标题】:Django check CSRF token manuallyDjango 手动检查 CSRF 令牌
【发布时间】:2015-06-09 20:21:57
【问题描述】:

我正在实现一个使用 API 密钥或 CSRF 令牌的 API。目标是让 Web 应用程序(受 CSRF 保护)或第三方应用程序(受 API 密钥保护)都可以使用它。

基本上对每个请求(全部通过 POST),我都会检查是否有 API 密钥。如果有一个有效的,那很好。如果没有,我想回退到验证 CSRF。

我可以调用一个函数来自己验证 CSRF 吗?视图本身是 @csrf_exempt,因为 API 密钥需要工作。

【问题讨论】:

  • 您不需要检查每个请求,因为 CSRF 令牌应该只用于 POST 和 PUT 请求。其次,您无法验证 CSRF 令牌,除非您在每个请求上都生成它,并且您的验证是可选。 CSRF 令牌与 API 密钥不同。请说明为什么需要 CSRF。

标签: django django-csrf csrf-protection


【解决方案1】:

您可能可以继承 CsrfViewMiddleware 类并覆盖 process_view 方法。然后包含您的自定义中间件,而不是默认的 CSRF 中间件。

from django.middleware.csrf import CsrfViewMiddleware

class CustomCsrfMiddleware(CsrfViewMiddleware):

    def process_view(self, request, callback, callback_args, callback_kwargs):
        if request.META.get('api_key'):
            # process api key
        else:
            return super(CsrfViewMiddleware, self).process_view(...)

【讨论】:

  • 为了向其他人澄清,为了使用您的自定义中间件,请进入您的项目的 settings.py 文件,删除 MIDDLEWARE_CLASSES django.middleware.csrf.CsrfViewMiddleware 中的行并添加您自己的(即myApp.views.CustomCsrfMiddleware )。很好的解决方案,谢谢!
【解决方案2】:

您可以像这样使用内置的 csrf 验证:

from django.middleware.csrf import CsrfViewMiddleware

def check_csrf(request):
  reason = CsrfViewMiddleware().process_view(request, None, (), {})
  if reason:
    # CSRF failed
    raise PermissionException() # do what you need to do here

【讨论】:

  • "reason" 在我的情况下始终是“无”。这在 2022 年仍然有效吗? (我使用基于类的视图)
【解决方案3】:

我一直在访问CsrfViewMiddleware,就像Aldarund 显示的那样,但关于这种解决方案还有更多需要说明:

  1. 如果您在视图中执行测试,则可以直接返回reason。根据how Django middleware works,当process_view返回的不是None,那么它必须是HttpResponse对象,所以它只能被视图返回。

    在某些情况下,您可能不想直接返回 reason,但如果没有理由不这样做,我宁愿返回它,以与网站在其他情况下的行为保持一致。

  2. 1234563 @。 (是的,它可能会发生。我收到的请求被修改并通过CsrfViewMiddleWare 重新测试之后由于站点范围的配置,它已经被CsrfViewMiddleware 测试过。)但是,中间件在测试之后将csrf_processing_done 设置为request,并且如果再次调用它就不会重新测试它,因为这个标志。所以csrf_processing_done 必须重置为False 才能执行第二次测试。

以下是上述内容的说明:

from django.middleware.csrf import CsrfViewMiddleware

def view(request):
    request.csrf_processing_done = False
    reason = CsrfViewMiddleware().process_view(request, None, (), {})
    if reason is not None:
        return reason # Failed the test, stop here.

    # process the request...

【讨论】:

    【解决方案4】:

    就我而言,我想通过 CSRF 检查发布一些原始数据。

    所以,我在处理 POST 数据的视图中使用了这个装饰器 requires_csrf_token

    from django.views.decorators.csrf import requires_csrf_token
    
    @requires_csrf_token
    def manage_trade_allocation_update(request):
    

    在我的模板中,我添加了 csrf_token génération 并将其放入数据帖子中:

    {% csrf_token %}
    ...
    data['csrfmiddlewaretoken'] = document.querySelector('input[name="csrfmiddlewaretoken"]').value;
    

    通过这种机制,我可以将 CSRF 保护与手动 HTTP POST 请求一起使用。

    【讨论】:

      猜你喜欢
      • 2020-10-29
      • 1970-01-01
      • 2020-08-16
      • 2018-08-02
      • 2018-07-13
      • 2013-08-11
      • 2016-08-03
      • 2021-07-14
      • 2020-10-12
      相关资源
      最近更新 更多