正确累加X-Forwarded-For需每跳用$proxy_add_x_forwarded_for追加不覆盖,并在首跳和末跳启用real_ip_module校验可信代理IP段,后端应读X-Real-IP或修正后的$remote_addr而非直接解析XFF首段。

要在多级反向代理中正确累加 X-Forwarded-For,核心是每跳都“追加不覆盖”,且只信任已知可信代理传来的值。直接写死 $remote_addr 或盲目取第一个 IP,都会导致链路断裂或被伪造。
每一级代理必须用 $proxy_add_x_forwarded_for
这是 Nginx 内置变量,等价于 "$http_x_forwarded_for, $remote_addr",它自动判断:若上游没传 XFF 头,就只填当前 $remote_addr;若已传,则在末尾追加当前 $remote_addr,用逗号加空格分隔。
- 首跳(如公网入口 Nginx)收到客户端请求 → XFF 变成
192.0.2.1 - 第二跳收到时已有
192.0.2.1→ 追加为192.0.2.1, 203.0.113.5 - 第三跳收到
192.0.2.1, 203.0.113.5→ 变成192.0.2.1, 203.0.113.5, 10.10.20.30
所有中间代理统一配置这一行即可,无需手动拼接或条件判断。
首跳代理要区分真实客户端与伪造头
最外层代理(直连公网)不能无条件信任客户端发来的 XFF 头,否则攻击者可伪造 X-Forwarded-For: 1.1.1.1 污染整条链路。
- 若首跳只服务可信来源(如 CDN、内网 LB),应关闭对其 XFF 的继承,强制设为
proxy_set_header X-Forwarded-For $remote_addr - 若首跳需兼容部分可信外部代理(如 Cloudflare),则启用
real_ip_module,用set_real_ip_from明确声明其 IP 段,并开启real_ip_recursive on - 这样,Nginx 会自动剥离可信代理 IP,把 $remote_addr 修正为真实客户端 IP,再由
$proxy_add_x_forwarded_for安全追加
后端解析必须依赖可信链而非原始 XFF
最终应用不能直接取 X-Forwarded-For 的第一个值——那是最容易被伪造的位置。可靠做法是:
- 最后一级 Nginx 启用
real_ip_module,并配置所有上游代理的 IP 段(如set_real_ip_from 10.0.0.0/8、set_real_ip_from 172.16.0.0/12) - 设置
real_ip_header X-Forwarded-For和real_ip_recursive on,让$remote_addr自动变成最左非可信 IP - 后端优先读
X-Real-IP(由 Nginx 注入)或修正后的$remote_addr,而不是自行解析 XFF 字符串
避免常见错误配置
这些操作看似合理,实则破坏链路完整性:
-
proxy_set_header X-Forwarded-For $remote_addr—— 覆盖上游值,丢失原始客户端 IP - 中间层重复写
proxy_set_header X-Real-IP $remote_addr—— 把上一跳代理 IP 当作真实用户 - 未设
set_real_ip_from就启用real_ip_header—— 默认只信 127.0.0.1,导致全部识别失败 - 后端代码用
split(",")[0]直接取 XFF 首段 —— 忽略伪造风险,也绕过可信校验逻辑


















