Django HTTPS 部署中 CSRF 验证失败(403)的完整解决方案

1次阅读

Django HTTPS 部署中 CSRF 验证失败(403)的完整解决方案

django 在启用 httpS 后出现 csrf verification failed 错误,通常源于 nginx 反向代理配置缺失关键头信息、CSRF 设置与 https 不兼容,或 CSRF_TRUSTED_ORIGINS 未正确配置。本文系统梳理排查路径与修复方案。

django 在启用 https 后出现 csrf verification failed 错误,通常源于 nginx 反向代理配置缺失关键头信息、csrf 设置与 https 不兼容,或 `csrf_trusted_origins` 未正确配置。本文系统梳理排查路径与修复方案。

当 Django 应用从 HTTP 迁移至 HTTPS(尤其在 docker + Nginx + AWS EC2 的生产环境中),常遇到 403 forbidden: CSRF verification failed 错误——即使模板中已正确使用 {% csrf_Token %},且后端逻辑无变更。该问题并非 CSRF Token 生成或提交本身失效,而是 Django 无法正确识别请求来源的可信性与安全上下文,核心原因集中在三方面:Nginx 代理头转发缺失、Django 安全配置未适配 HTTPS、以及跨域与信任源设置不严谨。

✅ 关键修复步骤

1. 补全 Nginx 反向代理头(最常见原因)

默认 Nginx 配置若仅包含基础 proxy_pass 和 Host/X-Forwarded-For,将导致 Django 无法获知原始协议(https)及真实客户端 IP,进而拒绝 CSRF Token 校验。必须显式传递 X-Forwarded-Proto:

location / {     proxy_pass http://127.0.0.1:8000;  # 或你的 Gunicorn/Uvicorn 地址     proxy_set_header Host $host;     proxy_set_header X-Real-IP $remote_addr;     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;     proxy_set_header X-Forwarded-Proto $scheme;  # ? 必须添加!告知 Django 当前是 HTTPS     proxy_set_header X-Forwarded-Host $server_name; }

⚠️ 注意:$scheme 在 HTTPS 请求中值为 https,Django 依赖此头判断是否启用 CSRF_cookie_SECURE 策略。

2. 修正 Django settings.py 安全配置

原配置中存在两个严重问题:

  • CSRF_TRUSTED_ORIGINS 包含 http://localhost/(HTTP 协议),但生产环境已启用 HTTPS,且该条目末尾斜杠 / 是非法格式;
  • CORS_ORIGIN_WHITELIST 已被弃用(DRF 3.13+),应改用 CORS_ALLOWED_ORIGINS,且协议必须匹配(HTTPS)。

修正后的推荐配置(生产环境):

# settings.py SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')  # ? 显式启用代理 SSL 识别 CSRF_COOKIE_SECURE = True      # 仅通过 HTTPS 发送 CSRF Cookie SESSION_COOKIE_SECURE = True   # 同理,确保 Session Cookie 安全 SECURE_SSL_REDIRECT = True     # 强制 HTTP → HTTPS 重定向(可选但推荐)  # ✅ 正确格式:协议 + 域名(无路径,无尾部斜杠) CSRF_TRUSTED_ORIGINS = [     'https://example.co.in',     'https://www.example.co.in',     'https://localhost:8080',  # 开发时如需本地 HTTPS 测试 ]  # ✅ DRF CORS 配置(替代已废弃的 CORS_ORIGIN_WHITELIST) CORS_ALLOWED_ORIGINS = [     'https://example.co.in',     'https://www.example.co.in', ] CORS_ALLOW_CREDENTIALS = True  # 若前端携带 cookies(如 axios withCredentials: true)

3. 验证与调试建议

  • 清除浏览器缓存与 Cookie:旧的 HTTP 版本 CSRF Cookie 可能残留,导致冲突;
  • 检查浏览器开发者工具 → Application → Cookies:确认 csrftoken Cookie 的 Secure 属性已生效(仅 HTTPS 传输);
  • 临时启用 Django 日志,在 settings.py 中添加:
    LOGGING = {     'version': 1,     'disable_existing_loggers': False,     'handlers': {'console': {'class': 'logging.StreamHandler'}},     'loggers': {'django.security.csrf': {'handlers': ['console'], 'level': 'DEBUG'}}, }

    可定位具体拒绝原因(如 Referer checking failed 或 Origin checking failed)。

总结

CSRF 403 错误在 HTTPS 迁移后高频出现,本质是安全上下文链断裂:Nginx 未透传协议信息 → Django 误判请求不安全 → 拒绝校验 Token。解决需三方协同:Nginx 补全 X-Forwarded-Proto、Django 启用 SECURE_PROXY_SSL_HEADER 并严格配置 CSRF_TRUSTED_ORIGINS(HTTPS 协议 + 无路径)、前端确保 fetch/axios 请求 Origin 与配置一致。完成上述调整后,无需修改业务代码即可恢复正常 CSRF 验证流程。

text=ZqhQzanResources