Django与React解耦开发:CSRF令牌不匹配、Cookie持久化异常
问题根因定位
响应取值不匹配的本质
这是Django 4.0+版本调整CSRF机制后的正常表现,不属于代码bug:
Set-Cookie头中的csrftoken值,存储的是服务端生成的高熵原始CSRF密钥,对应示例里的KceWlQsdiQuM.......段- 自定义响应头
X-CSRFToken返回给前端的,是基于这份原始密钥动态计算生成的掩码验证令牌,对应示例里的Ymx3NCe5dwh.......段 - 两个值从设计逻辑上就不是完全相同的字符串,服务端校验时会将前端提交的掩码令牌解算,与Cookie中存储的原始密钥做一致性校验,算法匹配即可通过。老版本Django中Cookie存储内容和返回前端的令牌值完全一致,版本迭代后拆分了存储和验证逻辑,才会出现内容差异。
旧Cookie无法覆盖的原因
Django的CSRF Cookie更新有明确的触发条件,当前代码缺失关键触发逻辑:
- 定义的CSRF获取视图没有添加
@ensure_csrf_cookie装饰器,CsrfViewMiddleware默认不会在每次请求时主动刷新CSRF Cookie,只有被该装饰器标记的视图,才会触发Cookie的写入、更新流程 - 缺失触发逻辑时,中间件检测到请求已经携带有效CSRF Cookie,就不会在响应中下发新的Cookie值,导致旧值持续留存
- 配置项
CSRF_COOKIE_AGE = None会让CSRF Cookie变成会话级临时Cookie,只要浏览器会话不关闭,旧值会一直存在,进一步放大不更新的异常表现 - 配置项
CSRF_COOKIE_SAMESITE = 'Strict'在跨端口本地调试场景下,会导致浏览器跨源请求时直接不携带已有Cookie,也会干扰Cookie的正常更新流程
修复方案
- 修改Django端CSRF视图代码,补全必要的装饰器逻辑:
from django.middleware.csrf import get_token, ensure_csrf_cookie from django.http import JsonResponse @ensure_csrf_cookie def get_csrf_token(request): csrf_token = get_token(request) response = JsonResponse({'detail': 'CSRF cookie set'}) response['X-CSRFToken'] = csrf_token return response
- 调整CSRF相关配置适配前后端分离场景:
- 将
CSRF_COOKIE_AGE = None改为合理的长过期值(如Django默认的31449600秒),解决会话级Cookie临时留存的问题 - 本地跨端口调试时,将
CSRF_COOKIE_SAMESITE临时改为'Lax',生产环境同域部署后再切回'Strict' - 保留
CSRF_COOKIE_HTTPONLY = True的配置,该配置可避免注入脚本读取CSRF Cookie,配合从X-CSRFToken响应头读取令牌的逻辑,是匹配当前前端方案的安全配置
- 将
- 前端现有fetch逻辑无需修改,确保所有需要CSRF校验的POST/PUT/DELETE请求,将之前获取的
csrf状态值设置到X-CSRFToken请求头即可,不需要手动从Cookie中读取令牌
验证流程
- 清理浏览器中已有的旧
csrftokenCookie,重新调用/api/csrf/接口 - 确认响应中会正常下发与原始密钥对应的Set-Cookie头,后续所有同域请求都会自动携带该Cookie
- 向后端提交携带CSRF头的请求,确认可以通过服务端的CSRF校验,无需纠结Cookie存储值和返回的令牌值是否完全一致
内容的提问来源于stack exchange,提问作者rpdjprog
相关产品推荐
相关产品推荐

