You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django跨域CSRF验证持续失败问题排查求助

问题排查:Django前后端分离CSRF验证失败及令牌丢失

前后端分离架构下,前端POST请求已在Cookie头携带csrftoken,单独放入请求头也无效,CSRF验证始终失败。更奇怪的是Django的request.META和request.headers里找不到该令牌信息。当前用Nginx做反向代理,已启用TLS加密。

核心困惑:前端已传递X_CSRFTOKEN和Cookie头,但后端检测不到。

注:移除http://dev.admin.lt配置项时,会出现如下错误:

(Origin checking failed - http://dev.admin.lt does not match any trusted origins.): /auth/login/

Django & CORS配置(中间件顺序已正确配置)

CORS_ALLOWED_ORIGINS = [
    "https://127.0.0.1",
    "https://admin.lt",
    "https://dev.admin.lt",
    "https://api.admin.lt",
    "http://dev.admin.lt", # NOTE, without this we get another error
]


CSRF_TRUSTED_ORIGINS = [
    "https://127.0.0.1",
    "https://admin.lt",
    "https://dev.admin.lt",
    "https://api.admin.lt",
    "http://dev.admin.lt" # NOTE, without this we get another error
]


CORS_ALLOW_CREDENTIALS = True

CSRF_COOKIE_SECURE = True
CSRF_COOKIE_HTTPONLY = True
CSRF_COOKIE_SAMESITE = None
CSRF_COOKIE_DOMAIN = ".admin.lt"

# Is this actually doing anything?
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = None
SESSION_COOKIE_DOMAIN = ".admin.lt"

后端捕获的请求头信息

ipdb> request.headers
{'Content-Length': '', 'Content-Type': 'text/plain', 'Connection': 'upgrade', 'Host': 'api.domain.lt', 'X-Forwarded-For': '123.123.123.202', 'Cookie': 'csrftoken=caOdoVlJeaAxUzXLtQvjhgEXunWX5K5V; sessionid=jajl1faqtfkmsk9q8ykbjge6obk14wwh', 'Origin': 'http://dev.domain.lt', 'Accept': '*/*', 'Accept-Language': '*', 'Sec-Fetch-Mode': 'cors', 'User-Agent': 'node', 'Accept-Encoding': 'br, gzip, deflate'}

Nginx反向代理配置

server
{
    server_name api.domain.lt;

    client_max_body_size 500m;

    #auth_basic "Restricted Content";
    #auth_basic_user_file /etc/nginx/.htpasswd;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
    proxy_set_header X-Forwarded-For $remote_addr;

    location /
    {
        proxy_pass http://localhost:8000;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/api.domain.lt/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/api.domain.lt/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

排查方向建议

  1. 域名不一致问题:请求头里的Origin是http://dev.domain.lt,但配置里的信任源是dev.admin.lt,二者完全不匹配。先统一域名(比如把配置里的dev.admin.lt改成dev.domain.lt),CSRF验证会严格校验Origin与信任源的一致性。

  2. Secure Cookie与HTTP Origin冲突:设置了CSRF_COOKIE_SECURE = True意味着Cookie仅通过HTTPS传输,但前端Origin是HTTP的http://dev.domain.lt,浏览器会拒绝在HTTP环境下发送Secure Cookie。要么把前端切换到HTTPS,要么临时将CSRF_COOKIE_SECURE设为False测试(生产环境不建议)。

  3. Nginx代理头缺失:Django需要识别请求来自HTTPS,否则会认为请求是HTTP,导致Secure Cookie不生效。在Nginx的proxy_set_header中添加:

    proxy_set_header X-Forwarded-Proto $scheme;
    

    同时在Django配置中添加:

    SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
    USE_X_FORWARDED_HOST = True
    
  4. CSRF_COOKIE_HTTPONLY的影响:CSRF_COOKIE_HTTPONLY = True会禁止前端JS读取Cookie中的csrftoken,这会导致前端手动设置X_CSRFTOKEN头时可能拿到旧值或空值。可以临时将CSRF_COOKIE_HTTPONLY设为False,测试前端是否能正确获取并传递令牌。

  5. Cookie域名匹配问题:CSRF_COOKIE_DOMAIN = ".admin.lt",但请求的API域名是api.domain.lt,前端Origin是dev.domain.lt,三个域名主域不一致(admin.lt vs domain.lt),导致Cookie无法跨域传递。需要将Cookie域名统一为.domain.lt,或确保前后端API在同一主域下。


内容的提问来源于stack exchange,提问作者Džiugas Bižokas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 23:23:15