Nginx 反向代理导致 API 鉴权头丢失报错 403 如何解决?

文章导读
这个问题通常是因为 Nginx 配置中缺少 proxy_set_header 指令,或者自定义头包含下划线被默认丢弃,导致后端服务收不到凭证而拒绝请求。
📋 目录
  1. A 命令速用版
  2. B 为什么会这样
  3. C 分步处理
  4. D 怎么验证是否生效
  5. E 安全与兼容性注意事项
  6. F 常见坑
  7. G 参考来源
A A

这个问题通常是因为 Nginx 配置中缺少 proxy_set_header 指令,或者自定义头包含下划线被默认丢弃,导致后端服务收不到凭证而拒绝请求。

先说结论:大多数情况是 Nginx 配置中缺少 proxy_set_header 指令,或者自定义头包含下划线被默认丢弃。

  • 先确认:查看后端应用日志,确认请求到达时是否缺少特定 Header。
  • 先处理:在 Nginx location 块中显式配置 proxy_set_header 传递鉴权头。
  • 再验证:使用 curl 携带头信息请求,观察后端响应是否恢复正常。

命令速用版

server {
    listen 80;
    server_name example.com;
    # 若自定义头包含下划线,需在 server 或 http 块开启此选项
    underscores_in_headers on;

    location / {
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        # 显式传递 Authorization 头,避免被其他配置覆盖
        proxy_set_header Authorization $http_authorization;
    }
}

为什么会这样

Nginx 作为反向代理时,默认会透传大多数请求头,但可能因配置覆盖或包含下划线而丢失。默认情况下,为了安全和规范,Nginx 会忽略包含下划线的请求头,除非显式开启选项。虽然 Authorization 头默认会被透传,但显式声明可避免被其他配置覆盖,具体取决于后端框架的期望和 Nginx 版本行为。

分步处理

1. 检查后端日志:确认后端收到请求时,鉴权头是否存在。如果日志显示头为空或缺失,说明在 Nginx 层丢失。

2. 修改 Nginx 配置:在对应的 server 或 location 块中,添加 proxy_set_header 指令。变量名格式为 $http_头名称(小写,横线变下划线)。

3. 处理下划线问题:如果你的鉴权头名称包含下划线(例如 X_Custom_Token),需要在 http 或 server 块中设置 underscores_in_headers on;。

4. 重载配置:执行 nginx -t 检查语法,然后 nginx -s reload 生效。

怎么验证是否生效

使用 curl 命令模拟请求,verbose 模式可以看到发送的头:

Nginx 反向代理导致 API 鉴权头丢失报错 403 如何解决?
curl -v -H "Authorization: Bearer token123" http://your-nginx-domain/api

同时观察后端日志,确认该头值是否已正确接收。如果后端返回 200 而非 403,说明修复成功。

安全与兼容性注意事项

1. CGI 环境冲突:开启 underscores_in_headers 可能导致与 CGI 环境的头名解析冲突,因为 CGI 规范通常将下划线转换为横线。

2. 安全风险:盲目开启 underscores_in_headers 可能引入 HTTP 请求走私风险,建议仅在确需传递含下划线自定义头时开启。

3. 配置层级:underscores_in_headers 指令仅支持 http 或 server 上下文,不可配置在 location 块中。

常见坑

1. 变量名大小写:Nginx 变量 $http_authorization 对应请求头 Authorization,横线在变量名中通常变为下划线。

2. 下划线默认丢弃:RFC 规范建议头名不含下划线,Nginx 默认遵循此建议丢弃含下划线的头,自定义鉴权头容易踩坑。

3. 多个 proxy_set_header:如果在不同层级重复配置,后配置的可能会覆盖先配置的,注意继承关系。

参考来源

  • Nginx Official Documentation, ngx_http_proxy_module, proxy_set_header, https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header
  • Nginx Official Documentation, ngx_http_core_module, underscores_in_headers, https://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers