django默认启用csrf中间件,但需手动添加{% csrf_token %}或x-csrftoken头,否则校验失败返回403;中间件仅对带会话的post/put/patch/delete请求校验,不自动注入token。

直接说结论:Django默认已启用CSRF中间件,但不加{% csrf_token %}或不传X-CSRFToken头,等于没防护。
为什么Django开了CsrfViewMiddleware还被403?
因为中间件只校验,不自动注入。它只在请求方法为POST/PUT/PATCH/DELETE且带会话(session)时触发校验,但不会帮你往表单里塞token,也不会替fetch读cookie发头。
- 常见错误现象:表单提交返回
403 Forbidden,控制台看不到csrfmiddlewaretoken字段 - 开发环境容易忽略:用
curl或Postman测试时没带Cookie和token,误以为中间件坏了 - 关键点:中间件对
GET、HEAD、OPTIONS请求不校验,也不拦静态文件(如/static/路径走StaticFilesHandler或Nginx)
Django模板中漏掉{% csrf_token %}怎么办
所有含状态变更的HTML表单都必须显式插入这个模板标签,否则浏览器发不出合法token。
- 必须加的位置:
<form method="post">...</form>内部,紧贴<form></form>开始后 - 不要写成
<input name="csrf_token" value="{{ csrf_token }}">——Django不认这个name,得用csrfmiddlewaretoken - 如果用了自定义
name(比如my_csrf),需同步配置CSRF_FIELD_NAME = 'my_csrf' - Admin页面也受保护,但Django已自动注入,不用你操心;自定义Form必须手动加
fetch发AJAX POST总被拒,jQuery却没事?
jQuery默认从csrftoken Cookie读值并设X-CSRFToken头,fetch不会——你得自己干。
- 别用
document.cookie.match(/csrftoken=([^;]+)/)[1]:正则在Cookie含特殊字符时会崩,且SameSite=Lax下可能读不到 - 推荐做法:服务端在
里塞<meta name="csrf-token" content="{{ csrf_token }}">,前端用document.querySelector('meta[name="csrf-token"]').getAttribute('content')取 - fetch示例:
const token = document.querySelector('meta[name="csrf-token"]').getAttribute('content'); fetch('/api/submit/', { method: 'POST', headers: { 'X-CSRFToken': token, 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); - 若用
@csrf_exempt绕过,请确认这是真实业务需要(如Webhook接收),不是图省事
前后端分离项目里CSRF中间件为啥没反应?
因为CsrfViewMiddleware依赖SessionMiddleware,而纯Token/JWT认证的API通常不启session。
- 典型表现:DRF接口返回200,但
request.COOKIES.get('csrftoken')为空,中间件根本没进校验逻辑 - 解决路径一:强制启用session(加
SessionAuthentication),让中间件生效 - 解决路径二:放弃CSRF中间件,改用
Origin头校验 + 敏感操作二次确认(如短信验证码) - 注意:
ensure_csrf_cookie()视图装饰器会在响应里写入csrftokenCookie,适合前端首次加载页面时“预种”token,但它不触发校验
最易被忽略的一点:开发时用HTTP本地调试,却把CSRF_COOKIE_SAMESITE硬设成None,结果浏览器直接丢掉Cookie——SameSite=None必须配CSRF_COOKIE_SECURE = True(即HTTPS),否则无效。保持默认Lax就行。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











