让Django、VUE、CORS和CSRF使用真实世界的示例

让Django、VUE、CORS和CSRF使用真实世界的示例,django,vue.js,django-rest-framework,django-csrf,django-cors-headers,Django,Vue.js,Django Rest Framework,Django Csrf,Django Cors Headers,我真的卡住了。这就是我要做的 保持CSRF开启请不要告诉我把它关掉 我有一个由Django和Django Rest框架运行的API应用程序 我有一个Vue运行的前端应用程序 我已经安装了django cors头来管理cors 在当地一切都很好。一旦我将其投入生产,我就开始出现CSRF错误。以下是每件事的工作原理 我在各地都看到了答案,从关闭CSRF到允许所有事情都进行。我想把这件事做好,而不仅仅是把事情关了,把所有的事情都打开,然后以一个安全漏洞告终 所以,这就是我所拥有的 已安装: djang

我真的卡住了。这就是我要做的

  • 保持CSRF开启请不要告诉我把它关掉
  • 我有一个由Django和Django Rest框架运行的API应用程序
  • 我有一个Vue运行的前端应用程序
  • 我已经安装了django cors头来管理cors
  • 在当地一切都很好。一旦我将其投入生产,我就开始出现CSRF错误。以下是每件事的工作原理

    我在各地都看到了答案,从关闭CSRF到允许所有事情都进行。我想把这件事做好,而不仅仅是把事情关了,把所有的事情都打开,然后以一个安全漏洞告终

    所以,这就是我所拥有的

    已安装: django cors收割台 django rest框架 嵌套路由器 ... 及其他

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

    让请求工作得很好。 选项请求似乎有效

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

    对于我的CORS,我在另一个
    中间件之前安装了
    'corsheaders.middleware.corsmidleware'

    那么我的CORS设置是:

    CORS_ALLOW_CREDENTIALS = True
    CORS_ORIGIN_WHITELIST = (
        '*.websitename.com',
    )
    
    CSRF_TRUSTED_ORIGINS = [
        "api.websitename.com",
    ]
    
    我的CSRF设置是:

    CORS_ALLOW_CREDENTIALS = True
    CORS_ORIGIN_WHITELIST = (
        '*.websitename.com',
    )
    
    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)
        })
      }
    }
    
    我的想法是,一旦应用程序加载到浏览器中,我就会得到一个CSRF令牌。但即使这样,当应用程序尝试执行除GET或选项之外的任何操作时,我也会遇到失败的CSRF令牌错误

    以下是返回令牌的视图,以防您成为古玩:

    class CSRFTokenView(APIView):
        permission_classes = (permissions.AllowAny,)
    
        @method_decorator(ensure_csrf_cookie)
        def get(self, request):
            return HttpResponse()
    

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

    到目前为止,解决这个问题最简单的方法是为来自同一领域的所有东西提供服务。您可以将CDN或代理直接调用
    /api
    到一台服务器,其余调用到前端服务器。这样就根本不需要担心CORS

    要使其正常工作,我认为您只是缺少AXIOS配置中的
    with credentials=true
    。Django要求发送CSRF cookie,如果未设置
    withCredentials
    ,则不会通过跨源请求发送cookie

    axios.interceptors.request.use(function (config) {
      config.withCredentials = true
      return config
    })
    
    另一个可能缺少的设置是Djano的
    会话\u COOKIE\u域
    。您应该这样设置:

    SESSION_COOKIE_DOMAIN=".mywebsite.com"
    
    第一个点很重要,因为它告诉Django,然后告诉web浏览器为
    *.mywebsite.com
    使用cookie,包括
    api.mywebsite.com


    如果所有操作仍然失败,我建议在Django的CSRF中间件上设置一个断点,看看缺少了什么使其正常工作。

    首先,您要使用:

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

    使用axios时,CSRF设置非常简单:

    import axios from 'axios'
    
    axios.defaults.xsrfHeaderName = 'X-CSRFToken'
    axios.defaults.xsrfCookieName = 'csrftoken'
    
    因此,您应该使用CSRF强制执行安全会话。几乎。要引用上面的链接页面,请执行以下操作:

    警告:创建登录页面时,请始终使用Django的标准登录视图。这将确保您的登录视图得到适当保护

    REST框架中的CSRF验证工作原理与标准Django略有不同,因为需要支持对相同视图的基于会话和非会话的身份验证。这意味着只有经过身份验证的请求才需要CSRF令牌,匿名请求可以在没有CSRF令牌的情况下发送。此行为不适用于登录视图,登录视图应始终应用CSRF验证

    这很棘手-您要么只需使用Django服务器端视图,这会使SPA设计变得更加复杂,要么在DRF中重新创建登录和其他身份验证视图,但要注意的是,使用方法装饰器在这些“匿名”视图上强制CSRF。显然,对于使用令牌的客户端,这些视图将中断,因此您可能希望对这些客户端使用不同的端点(可能重新使用相同的基类)。因此,浏览器登录使用/auth/browser/login/和移动登录/auth/mobile/login/,前者使用@csrf\u protect包装


    在研究contrib auth源代码之后,从头开始重新创建登录和其他auth视图应该仔细进行;对于一般的需求,我会推荐预先存在的解决方案,如和。然而,django rest auth包并不是为浏览器前端设计的,它强制使用令牌生成,而且您需要按照上述方式包装视图。另一方面,all auth为JS客户端提供AJAX响应,这可能是一个更好的选择。

    我已经完成了您在上述域中所说的内容。问题是,如果我统治世界的邪恶计划得以实现,API最终将成为一种服务。所以我需要把它作为一个单独的实例。我正在研究你建议的其他选择。它仍然可以是一个单独的例子。这取决于你的设置。例如,在AWS中,使用CloudFront在S3上创建静态文件是很常见的。在这种情况下,您可以让CloudFront指向API实例的一些URL,其余的指向S3。您还可以在API.mywebsite.com和mywebsite.com/API中公开API。