【问题标题】:django rest framework csrf token missing or incorrectdjango rest 框架 csrf 令牌丢失或不正确
【发布时间】:2017-10-02 15:25:58
【问题描述】:

你好,我正在使用 django rest-auth,我在 /password/change/ 中遇到了这个问题,它总是返回 csrf 令牌丢失或不正确的问题: 我正在向我正在开发的 android 应用程序发出请求 我的设置是:

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.sites',

'rest_framework',
'rest_framework.authtoken',

'rest_auth',
'rest_auth.registration',

'allauth',
'allauth.account',
'allauth.socialaccount',

]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.locale.LocaleMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.TokenAuthentication',
    )
}

版本: django-rest-auth==0.9.1

djangorestframework==3.6.2

【问题讨论】:

  • 解释你是如何使用 FORM 来执行请求的?您需要将令牌添加到表单中。
  • @Todor 我已经编辑了请求是由 android 应用提出的问题

标签: django django-rest-framework django-rest-auth


【解决方案1】:

解决方案很简单:您需要在提出请求时添加CSRF token。具体来说,您将如何做到这一点,我们无法回答,因为我们不知道您是如何提出请求的。即显示一些代码

【讨论】:

  • 请求是由 android 应用程序发出的,我注意到我已经从应用程序调用了 api 端点的表单或模板
  • @amirhattab 显示您用于调用端点的代码。
  • Ion.with(this).load("POST","127.0.0.1:8000/auth/password/change/")
  • @amirhattab 那么这是使用 Ionic 框架吗?必须有某种方法可以传入POST 数据。使用它来传递 CSRF 令牌。
【解决方案2】:

您是否正确存储和转发来自 Android 网络库的 cookie?我对 Ionic/Android 不太熟悉,但是 Django 的 CSRF 检查工作方式是这样的:

  • 检查是否在正文中提供了 CSRF 令牌为 csrfmiddlewaretoken
  • 如果不存在此类参数,请检查名为 csrftoken 的 cookie
  • 如果不存在此类 cookie,则回退到 HTTP_X_CSRFTOKEN 标头

cookie 名称和标头名称可以在设置中自定义。

所以我的意思是,您在上面使用什么方法发送 CSRF 令牌?在移动设备上,通常很难为请求获取 CSRF 令牌,因为客户端会生成表单(在 Web 上,Django 会生成表单并注入 CSRF 令牌)。

也就是说,使端点 CSRF 豁免也很常见,而且您似乎在为这些端点使用第三方库,所以我不确定它为什么需要 CSRF 令牌。您可以查看项目的文档。

另一种可能性是您在该 URL 上绑定了自己的视图,并且您访问的是该视图,而不是您正在使用的库中的视图。这有点难说。为什么不先尝试使用 DRF 的 Browsable API 请求?

【讨论】:

    【解决方案3】:

    在阅读了 django rest framework 官方的文档后,@Todor comment 提供了很多帮助,我意识到我应该只将 TokenAuthentification 放在其余身份验证类中,因为 sessionAuthentication 期望在请求但 android 无法提供,所以我在每个请求中都使用doc 中的令牌,就是这样!

    【讨论】:

    • 使用 Header Editor 之类的扩展来使用 Browserable API 或默认有 SessionAuthentication 要求的 Swagger。
    【解决方案4】:
    REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
    )
    }
    

    从 DEFAULT_AUTHENTICATION_CLASSES 中删除 'rest_framework.authentication.SessionAuthentication',如果您仍然需要 DRF 的可浏览 api 视图,请在 chrome 中使用 ModHeader

    【讨论】:

      【解决方案5】:

      当我尝试在 Apache 服务器上托管我的网站时出现此错误。 如果我在没有 Apache 服务器(python manage.py runserver)的情况下运行,一切都很好。

      要解决此错误: 打开 Apache 配置文件 - httpd.conf 添加以下行:

      WSGIPassAuthorization On
      

      【讨论】:

        【解决方案6】:

        这是我的快速解决方案,它不适合生产,除非您使用更改分叉其余框架存储库......而且它会禁用 SessionAuthentication 的功能。

        如果您打算将您的 api 与移动应用程序等无浏览器前端一起使用,该前端不允许发出跨站点请求(因为没有可以发出请求的浏览器,即应用程序将无法打开其他人发送给您的链接/您无法在其中浏览传统的网络)然后就这么简单:

        要删除该功能,请转到 rest_framework 站点包。它里面是一个 authentication.py 文件,里面有一个名为“SessionAuthentication”的类。这里有一个 enforce_csrf() 函数,它通过在请求中不存在 csrf 令牌时引发异常来强制执行 csrf。简单注释掉它的body,它就不再关心csrf了。

        这是 authentication.py SessionAuthentication 类的样子,请执行以下操作:

        class SessionAuthentication(BaseAuthentication):
        
            def authenticate(self, request):
                """
                Returns a `User` if the request session currently has a logged in user.
                Otherwise returns `None`.
                """
        
                # Get the session-based user from the underlying HttpRequest object
                user = getattr(request._request, 'user', None)
        
                # Unauthenticated, CSRF validation not required
                if not user or not user.is_active:
                    return None
        
                self.enforce_csrf(request)
        
                # CSRF passed with authenticated user
                return (user, None)
        
            def enforce_csrf(self, request):
                """
                Enforce CSRF validation for session based authentication.
                """
                ##### Comment Out Below:  ###########
                # check = CSRFCheck()
                # # populates request.META['CSRF_COOKIE'], which is used in process_view()
                # check.process_request(request)
                # reason = check.process_view(request, None, (), {})
                # if reason:
                #     # CSRF failed, bail with explicit error message
                #     raise exceptions.PermissionDenied('CSRF Failed: %s' % reason)
        

        因此,如果您想知道这是否是一个坏主意,因为所有请求都是有意在移动应用程序内发出/在大多数情况下由移动应用程序专门控制,因此它不会在与浏览器。用户很难不小心点击链接或脚本。请注意,这并不能完全修复漏洞,但它发生的可能性极小,而且很可能不会直接通过移动应用程序发生

        【讨论】:

          【解决方案7】:

          我想使用 SessionAuthentication 让当前用户处于休息视图中,我解决了它在每个请求中发送带有令牌值的授权标头,我也在使用 JSON Web 令牌身份验证

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-07-14
            • 1970-01-01
            • 2021-11-13
            • 2012-04-20
            • 2012-09-25
            • 1970-01-01
            • 1970-01-01
            • 2016-05-12
            相关资源
            最近更新 更多