长期未更新的Django站点突发用户需清Cookie获取CSRF token报错问题
故障根因
- 问题本质是浏览器Cookie安全策略更新:Chrome 80+、iOS 14.5及之后的安卓主流浏览器,对未指定
SameSite属性的Cookie默认采用SameSite=Lax规则,跨站场景下未同时设置Secure和SameSite=None的Cookie会被直接拦截。 - 你的站点数月未更新代码,历史下发的CSRF Cookie未携带符合新规则的
SameSite属性,被浏览器拦截后Django读取不到对应Cookie就会抛出CSRF Failed: CSRF cookie not set.报错。 - 会话Cookie和CSRF Cookie是两个独立的Cookie,你站点的会话Cookie属性符合浏览器规则,所以用户依然保持登录状态,只有CSRF校验失败。
- 手动清除Cookie后恢复的原因是:旧的不符合规则的Cookie被删除后,站点会重新下发新的Cookie,正常通过校验。
无感知修复方案(无需用户手动清理Cookie)
- 调整Django配置文件
settings.py中Cookie的SameSite属性,匹配你的站点场景:- 单站点无跨站请求(无iframe嵌入、无跨站API调用)的场景,添加如下配置:
CSRF_COOKIE_SAMESITE = 'Lax' SESSION_COOKIE_SAMESITE = 'Lax' - 存在跨站请求的场景,必须同时开启
Secure属性(要求站点必须走HTTPS),添加如下配置:CSRF_COOKIE_SAMESITE = 'None' CSRF_COOKIE_SECURE = True SESSION_COOKIE_SAMESITE = 'None' SESSION_COOKIE_SECURE = True
SameSite属性配置,建议先升级到对应LTS版本的最新小版本(如2.2.x、3.2.x),小版本升级不会改动核心API,兼容旧代码。 - 单站点无跨站请求(无iframe嵌入、无跨站API调用)的场景,添加如下配置:
- 修改CSRF Cookie的默认名称,让浏览器自动忽略旧的无效Cookie,无需用户手动清理:
在settings.py中添加如下配置,名称可自定义,只要和原默认的csrftoken不同即可:
配置上线后,Django会直接读取新名称的CSRF Cookie,找不到就自动为用户下发新的符合规则的Cookie,用户全程无感知,不会再遇到报错。CSRF_COOKIE_NAME = 'csrftoken_v2' - 额外排查点:如果你的站点接入了CDN、反向代理或者WAF,检查相关配置是否会过滤
Set-Cookie响应头,或者修改Cookie的属性,确保Django下发的Cookie属性可以正常传递到用户浏览器。
内容的提问来源于stack exchange,提问作者Leah Sapan
相关产品推荐
相关产品推荐

