Django应用本地运行正常 部署至Heroku出现CSRF验证失败报错
给profile视图加@csrf_exempt解决不了问题,是因为登录、注册、管理员登录走的都不是profile视图逻辑,Django自带的认证视图、admin视图不会受这个装饰器影响,按下面的步骤逐一排查即可:
1. 配置可信CSRF源
Django 4.0及以上版本强制校验请求源,Heroku部署的域名必须显式加入可信列表,否则所有POST请求都会被CSRF校验拦截。
打开项目的settings.py,添加如下配置:
# 替换为你自己的Heroku应用域名,必须带协议头 CSRF_TRUSTED_ORIGINS = [ "https://<你的应用名>.herokuapp.com", # 如果绑定了自定义域名,一并加入列表 ]
注意:Heroku默认提供的域名全为HTTPS协议,不要写错成HTTP,否则配置不生效
2. 配置反向代理信任
Heroku的流量是通过前置反向代理转发到你的应用实例的,没配置代理信任的话,Django会把HTTPS请求误识别为HTTP请求,导致CSRF校验时源站匹配失败。
在settings.py中添加配置:
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
如果开启了SECURE_SSL_REDIRECT = True强制HTTPS跳转,要把上面的代理配置放在SSL重定向配置之前,避免出现头识别错误。
3. 检查CSRF Cookie配置
CSRF校验依赖Cookie传递令牌,配置错误会导致浏览器无法正常写入、携带CSRF Cookie:
- 生产环境(Heroku部署环境)下将
CSRF_COOKIE_SECURE设为True,本地开发环境设为False,建议通过环境变量区分两个环境的配置 - 生产环境下将
SESSION_COOKIE_SECURE同步设为True - 无特殊跨域需求不要修改
CSRF_COOKIE_DOMAIN配置,保持默认留空即可适配Heroku二级域名 CSRF_COOKIE_SAMESITE保持默认值'Lax'即可覆盖绝大多数场景,不要随意设为'Strict'避免跨子域请求被拦截
4. 表单与请求校验
如果是自定义的登录、注册表单,确认所有POST表单内都添加了{% csrf_token %}模板标签;如果是前后端分离通过AJAX提交请求,确认请求头中携带了从Cookie中读取的X-CSRFToken值。
注:如果Django自带的Admin后台登录也报CSRF错误,这一步可以直接跳过,Django默认生成的Admin表单已经内置了CSRF标签
5. 部署生效验证
配置修改完成后,执行以下命令推送代码到Heroku完成部署:
git add . git commit -m "fix: adjust csrf config for heroku production" git push heroku main
部署完成后,先清除浏览器中对应Heroku域名下的所有缓存、Cookie,再重新测试相关功能——本地残留的错误Cookie会导致CSRF校验持续失败。
安全提示:不要随意给登录、注册这类涉及账号权限的接口加
@csrf_exempt跳过校验,会直接让站点暴露在跨站请求伪造攻击风险下,正确配置上述参数才是合规解决方案。
内容的提问来源于stack exchange,提问作者Linh Chi Nguyen

