跨域 POST 请求的 CSRF 验证在生产中失败

Posted

技术标签:

【中文标题】跨域 POST 请求的 CSRF 验证在生产中失败【英文标题】:CSRF Verification fails in production for Cross Domain POST request 【发布时间】:2019-09-14 11:08:47 【问题描述】:

HTTP_X_CSRFTOKEN 标头与 csrftoken cookie 中的内容不匹配。

如何检查 cookie? Set-Cookie 不显示在跨域请求的响应标头中。

我已经按照以下中的说明进行操作:

CSRF with Django, React+Redux using Axios

有趣的是,我发现“X-CSRFTOKEN”在服务器请求标头上转换为“HTTP_X_CSRFTOKEN”。

在 localhost 下的开发环境中工作正常(尽管我使用 2 个不同的端口 - 一个用于 django,另一个用于我的前端)。

更新:

似乎没有为跨域请求正确设置 csrktoken cookie(尽管浏览器在请求标头中显示它),因此 X-CSRFTOKEN 没有被发送。

我最终添加了一个 API 调用,以使用 GET 请求返回当前 csrftoken,然后使用 X-CSRFTOKEN 标头将其发回。

【问题讨论】:

【参考方案1】:

您首先没有提到您是如何从服务器获取csrftoken 的,所以我假设它已经存在于您的浏览器中。 除了X-CSRFToken 标头,还使用withCredentials: true 在请求中包含cookie。 我正在使用 js-cookie 库从 cookie 中获取 csrftoken

import Cookies from 'js-cookie';

axios(
    url: 'http://localhost:8000/graphql',
    method: 'post',
    withCredentials: true,
    data: 
        query: `
            
                // Your query here
                 
        `
    ,
    headers: 
        "X-CSRFToken": Cookies.get('csrftoken')
    
)

如果您使用的是django-cors-headers,请将CORS_ALLOW_CREDENTIALS = True 添加到您的settings.py。否则,cookie 将不被接受。

【讨论】:

【参考方案2】:

您必须通过 CORS Access-Control-Expose-Headers 指令使 X-CSRFTOKEN 标头可访问。示例:

Access-Control-Expose-Headers: X-CSRFTOKEN

此标头必须由您的 API 或 Web 服务器设置,以便浏览器在 CORS 预检请求期间看到它。

【讨论】:

django-cors-headers 这样做。实际上正在发送标头。不是 cookie。尽管显示在 chrome devtools 的请求标头中。

以上是关于跨域 POST 请求的 CSRF 验证在生产中失败的主要内容,如果未能解决你的问题,请参考以下文章

CSRF 验证失败 - 当主机安全时,Referer 不安全

django CSRF 验证失败。请求中止

iPhone POST 到 Django 并获得 CSRF 验证失败

CSRF 验证失败。请求中止

Express + React:CSRF Coo​​kie 在生产中未定义,在本地工作

Django POST 请求失败