bigywater.tech
Flask · 122

CSRF 防护

CSRF 攻击在今天的浏览器里还成立吗?SameSite=Lax 能不能代替 CSRF token?GET 接口为什么不能改状态?这篇用 localhost 与 127.0.0.1 两个站点,在真实的 Chrome 里把攻击一次次打出来,再逐个看防护有没有用。

余额 1000 → 900
攻击成功时受害者账户的变化(没写 SameSite、或 SameSite=None 且无 token)
400
开了 CSRFProtect 后缺 token 的伪造 POST 得到的状态码
GET
修改状态的 GET 接口,Lax 与 CSRFProtect 都防不住

真实 Chrome 里的 CSRF

实测 · 本机执行输出
  [SameSite=Lax(显式写明),无 CSRF 防护,自动提交 POST 表单]
     服务端是否收到转账请求: True | 请求详情: [{'cookie_user': None, 'method': 'POST', 'sec_fetch_site': 'cross-site', 'status': 401}]
     转账是否成功: [] | 余额 1000
  [SameSite 未设置(Chrome 当 Lax),无 CSRF 防护,恶意页面自动提交 POST 表单]
     服务端是否收到转账请求: True | 请求详情: [{'cookie_user': 'victim', 'method': 'POST', 'sec_fetch_site': 'cross-site', 'status': 200}]
     转账是否成功: ['attacker'] | 余额 900
  [SameSite 未设置,无 CSRF 防护,恶意页面顶级导航到 GET 转账接口]
     服务端是否收到转账请求: True | 请求详情: [{'cookie_user': 'victim', 'method': 'GET', 'sec_fetch_site': 'cross-site', 'status': 200}]
     转账是否成功: ['attacker'] | 余额 900
  [SameSite=None + Secure,无 CSRF 防护,自动提交 POST 表单]
     服务端是否收到转账请求: True | 请求详情: [{'cookie_user': 'victim', 'method': 'POST', 'sec_fetch_site': 'cross-site', 'status': 200}]
     转账是否成功: ['attacker'] | 余额 900
  [SameSite=None + Secure,开了 CSRFProtect,自动提交 POST 表单]
     服务端是否收到转账请求: True | 请求详情: [{'cookie_user': 'victim', 'method': 'POST', 'sec_fetch_site': 'cross-site', 'status': 400}]
     转账是否成功: [] | 余额 1000
  [SameSite=None + Secure,开了 CSRFProtect,导航到 GET 转账接口]
     服务端是否收到转账请求: True | 请求详情: [{'cookie_user': 'victim', 'method': 'GET', 'sec_fetch_site': 'cross-site', 'status': 200}]
     转账是否成功: ['attacker'] | 余额 900

上一篇:HttpOnly、Secure、SameSite;下一篇:XSS 防护。

第 73 篇看过 Flask-WTF 的 token 校验细节。本篇的六种配置在同一个实验里按顺序列出,右边的分步演示逐个对照。

分步演示

CSRF 防护
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动。Flask-WTF 1.3.0(CSRFProtect)、本机 Google Chrome(无头模式)
    • 没有验证:Firefox 与 Safari 的 SameSite 默认值、没写 SameSite 时宽限期的具体时长与规则、Origin 与 Referer 头校验作为额外防线、JSON API 靠自定义头与 CORS 预检防 CSRF 的效果、登录 CSRF
    京ICP备2026067502号-1京公网安备11010502063487号