让Django,VUE,CORS和CSRF使用真实世界的例子

我真的被卡住了.这就是我想要做的.

>保持CSRF开启. – 请不要告诉我把它关掉.
>我有一个由Django和Django Rest Framework运行的API应用程序
>我有一个Vue运行的前端应用程序
>我已经安装了django-cors-headers来管理CORS

一切都很好用于当地.一旦我将其转移到生产环境,我就开始收到CSRF错误.一切都是如此.

我已经看到了各种各样的答案,从关闭CSRF到允许所有事情都做了.我想要做到这一点,而不仅仅是关闭并打开所有东西,最终得到一个安全漏洞.

所以,这就是我所拥有的.

安装:
Django的CORS报头
Django的休息框架
DRF-嵌套路由器
… 和别的

我在api.websitename.com上运行了api,并且在websitename.com上运行了Vue.js应用程序.

GET请求工作得很好.
OPTION请求似乎有效.

任何有风险的请求都不起作用.

对于我的CORS,我有’corsheaders.middleware.CorsMiddleware’,安装在我的其他MIDDLEWARE之前.

然后我的CORS设置是:

CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = (
    '*.websitename.com',
)

我的CSRF设置是:

CSRF_TRUSTED_ORIGINS = [
    "api.websitename.com",
]

无论我如何玩这些,我最终都会遇到CSRF令牌错误.

我在Vue App.vue文件中尝试过这样做的方法:

mounted () {
  this.getCSRFToken()
},
methods: {
  getCSRFToken () {
    return axios.get('token/').then(response => {
      axios.defaults.headers.common['x-csrftoken'] = Cookies.get('csrftoken')
    }).catch(error => {
      return Promise.reject(error.response.data)
    })
  }
}

我的想法是,一旦APP在浏览器中加载,我就会得到一个CSRF令牌.但即便如此,当应用程序尝试执行除GET或OPTION之外的任何操作时,我的CSRF令牌错误都会失败.

这是返回令牌的视图,这是你的好奇心:

class CSRFTokenView(APIView):
    permission_classes = (permissions.AllowAny,)

    @method_decorator(ensure_csrf_cookie)
    def get(self, request):
        return HttpResponse()

我意识到我可能会在这里混合问题,但任何可以帮助我解决问题的建议都是受欢迎的.

最佳答案 首先你要使用
SessionAuthentication

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

除了匿名用户之外,这将强制实施CSRF(稍后会详细介绍).对于浏览器前端,最简单的解决方案是在同一个域下同时拥有(浏览器)前端和后端 – 这可以让你避免使用CORS – 正如上面的评论所建议的那样.如果您有其他客户端,那么只需使用令牌(DRF令牌或JWT) – 但由于存在XSS攻击的危险,这些对于浏览器使用是不安全的(在localStorage中存储令牌本质上是不安全的).

当您使用axios时,CSRF设置很容易:

import axios from 'axios'

axios.defaults.xsrfHeaderName = 'X-CSRFToken'
axios.defaults.xsrfCookieName = 'csrftoken'

因此,您应该强制执行CSRF的安全会话.几乎.引用上面的链接页面:

Warning: Always use Django’s standard login view when creating login pages. This will ensure your login views are properly protected.

CSRF validation in REST framework works slightly differently to standard Django due to the need to support both session and non-session based authentication to the same views. This means that only authenticated requests require CSRF tokens, and anonymous requests may be sent without CSRF tokens. This behaviour is not suitable for login views, which should always have CSRF validation applied.

这是icky – 您要么只是使用Django服务器端视图,这会使您的SPA设计更复杂或在DRF中重新创建登录和其他身份验证视图,但需要注意使用@csrf_protect方法装饰器对这些“匿名”强制执行CSRF观点.显然,对于使用令牌的客户端,这样的视图会中断,因此您可能希望为这些使用不同的端点(可能重用相同的基类).因此,您的浏览器登录使用/ auth / browser / login /和您的移动登录/ auth / mobile / login /,前者使用@csrf_protect包装.

在研究contrib auth源代码后,应该从头开始重新创建登录和其他身份验证视图;对于vanilla要求,我建议使用预先存在的解决方案,如django-rest-authdjango-all-auth.然而,django-rest-auth软件包不是很好地设计用于浏览器前端并强制使用令牌生成,而且你需要如上所述包装视图.另一方面,all-auth为JS客户端提供AJAX响应,可能是更好的选择.

点赞