Django部署后CSRF验证失败Forbidden错误怎么修?配置该怎么改?

文章导读
部署后出现 CSRF 验证失败,通常是因为生产环境的域名、协议或代理配置与 Django 的安全设置不匹配,重点检查 CSRF_TRUSTED_ORIGINS 和 Cookie 安全选项。
📋 目录
  1. A 快速处理思路
  2. B 为什么会这样
  3. C 分步处理
  4. D 前端 AJAX 请求处理
  5. E 怎么验证是否生效
  6. F 常见坑
  7. G 参考来源
A A

部署后出现 CSRF 验证失败,通常是因为生产环境的域名、协议或代理配置与 Django 的安全设置不匹配,重点检查 CSRF_TRUSTED_ORIGINS 和 Cookie 安全选项。

先说结论:大多数情况是生产域名未加入信任列表或 HTTPS 配置不一致,需同步修改 settings.py 并重启服务。

  • 先确认:报错日志中的 Origin header 与实际访问域名是否一致
  • 先处理:在 settings.py 中补充 CSRF_TRUSTED_ORIGINS 配置
  • 再验证:刷新页面确认不再返回 403 Forbidden

快速处理思路

直接修改项目 settings.py 文件,找到 CSRF 相关配置项,将当前访问的域名和协议加入信任列表,同时检查允许的主机。

ALLOWED_HOSTS = [
    'your-domain.com',
    'www.your-domain.com'
]

CSRF_TRUSTED_ORIGINS = [
    'https://your-domain.com',
    'https://www.your-domain.com'
]

如果使用了 HTTPS,确保 CSRF_COOKIE_SECURE = True;如果站点被嵌入 iframe,检查 CSRF_COOKIE_SAMESITE 设置。

为什么会这样

Django 默认开启 CSRF 中间件保护,防止跨站请求伪造。在生产环境中,浏览器发送请求时会携带 Origin 或 Referer 头,Django 会核对这些头中的域名是否在信任列表内。如果部署后域名变更、使用了负载均衡或反向代理,导致请求头中的来源信息与 Django 配置不一致,就会拦截请求并返回 403 Forbidden。

分步处理

第一步:检查 ALLOWED_HOSTS

确保 settings.py 中的 ALLOWED_HOSTS 包含当前访问的域名。如果该项为空或不含当前域名,请求会在 CSRF 检查前被拒绝。

ALLOWED_HOSTS = [
    'example.com',
    'www.example.com',
    '.example.com'
]

第二步:配置 CSRF_TRUSTED_ORIGINS

Django 4.0 及以上版本要求显式声明信任的源。格式必须包含协议前缀(http:// 或 https://)。

CSRF_TRUSTED_ORIGINS = [
    'https://example.com'
]

第三步:检查 Cookie 安全设置

如果站点使用 HTTPS,建议设置 CSRF_COOKIE_SECURE = True,防止 Cookie 通过 HTTP 泄露。如果前端跨域调用且使用 HTTPS,可调整 CSRF_COOKIE_SAMESITENone 并必须设置 CSRF_COOKIE_SECURE = True

第四步:检查反向代理配置

Django部署后CSRF验证失败Forbidden错误怎么修?配置该怎么改?

Nginx 或 Apache 代理时,需确保传递了正确的 Host 和 X-Forwarded-Proto 头,否则 Django 可能误判协议类型。

Nginx 配置示例:

location / {
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://127.0.0.1:8000;
}

前端 AJAX 请求处理

前端使用 AJAX 提交时,需手动从 Cookie 读取 csrftoken 并添加到请求头 X-CSRFToken 中。

function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) {
            const cookie = cookies[i].trim();
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}

const csrftoken = getCookie('csrftoken');

// 在使用 fetch 或 axios 时设置 header
fetch('/api/endpoint/', {
    method: 'POST',
    headers: {
        'X-CSRFToken': csrftoken,
        'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)
});

怎么验证是否生效

1. 打开浏览器开发者工具,切换到 Network 标签页。

2. 刷新页面或提交表单,观察请求状态码是否从 403 变为 200。

3. 检查请求头中的 Cookie 是否包含 csrftoken,且响应中 Set-Cookie 正常写入。

4. 查看 Django 运行日志,确认没有新的 Forbidden 报错。

常见坑

1. 协议头缺失:CSRF_TRUSTED_ORIGINS 必须带 http:// 或 https://,只写域名无效。

2. 端口号问题:如果非标准端口(如 8000),信任列表中需包含端口号。

3. 多域名环境:如果有多个子域名或测试域名,需全部加入信任列表,不支持通配符。

参考来源