当请求中存在 CSRF 令牌时,“CSRF 会话令牌丢失”

jef*_*eff 7 python flask reactjs

我习惯Flask-WTF将其 CSRF 安全功能用于我的 API。正如标题所示,我从 API 获得的响应显示“CSRF 会话令牌丢失”。但是,在检查开发人员工具中的网络选项卡后,最初访问 API 返回的会话出现在 cookie 部分中。此外,CSRF 令牌存在于请求标头中。下面是一些图片来说明我的意思:

请求失败

在此输入图像描述

请求成功

在此输入图像描述


过程

  1. 客户端向 API 发出初始请求
  2. API 创建会话,在浏览器中设置 cookie,并在响应标头中返回 CSRF 令牌
  3. 客户端在每个后续请求中附加 CSRF 令牌

例子

前端是用React开发的,后端是用Python(Flask)开发的。两者均由Heroku托管。域名注册商位于GoDaddy,我使用Cloudflare作为我的 DNS 来重新路由流量并设置正确的域名。

示例请求如下所示:

const headers = {
   'Content-Type': 'application/json',
   'X-CSRF-Token': csrfToken 
};
...
const handleFormSubmission = async e => {
    e.preventDefault();
    await axios.post('https://backend.com/add-results', { tokenId: tokenId }, { withCredentials: true, headers: headers })
}
Run Code Online (Sandbox Code Playgroud)

并且后端有以下设置:

...
    CORS(app, origins=["https://www.example.com"], expose_headers=["Content-Type", "X-CSRFToken"], supports_credentials=True)  
...
    app.config['SESSION_COOKIE_SECURE'] = True
    app.config['SESSION_COOKIE_HTTPONLY'] = True
    app.config['REMEMBER_COOKIE_SECURE'] = True
    app.config['REMEMBER_COOKIE_HTTPONLY'] = True
    app.config['SESSION_COOKIE_DOMAIN'] = 'example.com' 
Run Code Online (Sandbox Code Playgroud)

笔记

当这个错误出现时,它是非常随机的。有时需要向 API 发出 6 次请求才能识别 CSRF 令牌。在所有 6 个失败的请求中,CSRF 令牌和会话 cookie 是相同的。

不确定发生了什么。

Sar*_*l N 2

我也遇到了同样的问题并解决了。我认为,显示此错误的原因有多种。这可能是我的应用程序实现或服务器配置中的问题。

我已经关注了这个博客来了解我的基本应用程序。

问题是我收到“CSRF 会话令牌丢失”。当我尝试登录生产服务器中的应用程序时的屏幕。这是一个误解。实际上,我已经在不同的浏览器中登录了该应用程序。然后,当我或任何其他用户尝试登录/注册时,我们将收到此错误。但不幸的是,不同的用户报告了相同的错误,他们用不同的解决方案解决了该错误。

  1. Flask-WTF:缺少 CSRF 令牌
  2. 由于缺少 CSRF,表单验证失败
  3. Flask WTF CSRF 会话令牌丢失,secret_key 未找到
  4. Flask CSRF 令牌缺失
  5. https://nickjanetakis.com/blog/fix-missing-csrf-token-issues-with-flask
  6. https://github.com/miguelgrinberg/flasky/issues/1
  7. https://medium.com/@sagar.pndt305/how-to-fix-the-csrf-token-issue-when-using-gunicorn-with-flask-66f04fc1a9b9

我在 VPS 中使用 Gunicorn 和 Ngnix 以及系统服务。在系统服务文件中,示例内容如下。代码是从另一个教程复制的。

[Unit]
Description=Gunicorn instance to serve myproject
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myproject
Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
ExecStart=/home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app

[Install]
WantedBy=multi-user.target
Run Code Online (Sandbox Code Playgroud)

我的问题是我的应用程序没有线程化。我必须配置 Gunicorn 以在线程模式下为应用程序提供服务。我从我分享的最后一个链接中得到了这个提示。

所以我改变了我的系统服务文件,如下所示。唯一的变化是--threadsGunicorn 命令中的参数。

[Unit]
Description=Gunicorn instance to serve myproject
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myproject
Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
ExecStart=/home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --threads 12 --bind unix:myproject.sock -m 007 wsgi:app

[Install]
WantedBy=multi-user.target 
Run Code Online (Sandbox Code Playgroud)

我不知道线程和CSRF令牌之间的关系。我也不知道最佳的工作线程数和线程数。现在问题已经解决了。我相信Flask中的线程和服务器会话有一定的关系。