Nginx 的 real_ip_header 与 X-Forwarded-For 看起来不对,怎么配?
Nginx real_ip_header 正确姿势:real_ip_header X-Forwarded-For + set_real_ip_from 限定可信代理网段;多层代理用 real_ip_recursive;防伪造原理与 FAQ。
正确姿势是三个指令配合:set_real_ip_from 声明可信代理网段 → real_ip_header X-Forwarded-For 指定从哪个头取真实 IP → 多层代理链加 real_ip_recursive on。 缺了 set_real_ip_from,X-Forwarded-For 谁都能伪造,等于没配。
标准配置
http {
# 可信的代理/负载均衡网段(你的 CDN、SLB、前置 Nginx)
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.16.0.0/12;
# CDN 厂商的官方 IP 段逐条列上
real_ip_header X-Forwarded-For;
real_ip_recursive on; # 多层代理时从右往左跳过可信 IP
...
}
工作原理(理解了就配不错)
请求经过"客户端 → CDN → SLB → Nginx"时,X-Forwarded-For 可能是:
X-Forwarded-For: 客户端IP, CDN节点IP
remote_addr 是直连 Nginx 的 SLB 地址。real_ip 模块的算法:
- 直连 IP 在
set_real_ip_from里 → 可信,开始从 XFF 右侧往左检查; real_ip_recursive on:跳过所有落在可信网段里的 IP,第一个不可信的 IP 就是真实客户端;remote_addr被改写为那个 IP,应用层拿到的就是真实来源。
常见翻车点
- 没设 set_real_ip_from:模块不生效,
remote_addr还是代理 IP——"配了没用"。 - 网段写窄了:代理换了出口 IP,Nginx 认为它不可信 → 取到的是代理自己的 IP 或 XFF 里错误的一格。
- 递归没开:多层代理下只回退一格,拿到的还是中间代理地址。
- 信任了客户端伪造:网段设得太宽(如
0.0.0.0/0),访客随手发个X-Forwarded-For: 8.8.8.8就伪装成功——基于 IP 的限流、审计全部失效。
验证
curl -H "X-Forwarded-For: 1.2.3.4" http://yoursite/debug-ip
# debug 接口回显 remote_addr,对照是否变为 1.2.3.4(仅当 curl 来源在可信段内)
再抓一条真实访问看 access log 里的 $remote_addr 是否已是真实客户端。
观测云对照
真实 IP 是访问日志里最重要的维度之一——风控、地域分析、异常排查全依赖它。日志接入观测云后,在日志查看器里按 $remote_addr 做地域分布、TOP 来源分析;IP 维度的突增告警还能帮你发现"限流规则因为拿到的是代理 IP 而形同虚设"这类配置事故。
常见问题(FAQ)
Q:CDN 厂商的 IP 段去哪找?
A:各厂商官网都公布回源 IP 段(通常提供 JSON/文本接口)。段会变,建议定期同步进配置,或用自动化工具生成。
Q:应用框架(如 Laravel/Express)还要再配信任代理吗?
A:要。Nginx 改的是自己的 $remote_addr;应用若从 X-Forwarded-For 取 IP,也得声明可信代理,否则同样会被伪造值欺骗。两层各管各的。
Q:CF-Connecting-IP 这类自定义头能用吗?
A:可以,real_ip_header CF-Connecting-IP;。但同样必须配合 set_real_ip_from 限定 Cloudflare 官方 IP 段,否则伪造更容易。