核心是信任链构建:最外层代理必须用$remote_addr重置xff,内层仅追加;nginx需配置set_real_ip_from白名单+real_ip_recursive on,使$remote_addr自动还原真实ip;后端应直接读x-real-ip或修正后的$remote_addr,而非原始xff。

处理 Nginx 代理环境下的 X-Forwarded-For(XFF)伪造攻击,核心不是“怎么读”,而是“信谁、从哪来、怎么传”。攻击者可随意添加或篡改 X-Forwarded-For: 1.2.3.4, 5.6.7.8,后端若直接取第一个 IP,就会被欺骗。真正可信的只有 TCP 连接对端地址——$remote_addr,它无法在应用层伪造。
只信任你明确配置的上游代理
Nginx 必须知道哪些 IP 是可信的代理(比如 CDN 回源段、公司 SLB 内网地址),其他来源的 XFF 一律丢弃或覆盖:
- 在
http块中用set_real_ip_from列出所有可信源,例如:set_real_ip_from 203.0.113.0/24;(Cloudflare)、set_real_ip_from 10.10.0.0/16;(内网负载均衡) - 启用
real_ip_header X-Forwarded-For;和real_ip_recursive on;,让 Nginx 正确解析多层代理链 - 配置后,
$remote_addr就会被自动修正为真实客户端 IP(前提是请求来自白名单 IP),后端应直接使用该变量,而非原始 HTTP 头
最外层代理必须重置 XFF
面向公网的第一跳 Nginx(如接用户浏览器或 CDN),是信任链起点。它收到的 $remote_addr 就是真实客户端 IP 或可信上一级代理 IP:
- 强制设为:
proxy_set_header X-Forwarded-For $remote_addr; - 禁用
$proxy_add_x_forwarded_for——它会拼接不可信的原始 XFF,引入风险 - 同时设置:
proxy_set_header X-Real-IP $remote_addr;,供后端直接读取
内层代理只负责追加,不采信前端 XFF
如果架构中有 WAF → 接入层 Nginx → 应用层 Nginx 多级代理,中间每一层都只能信任其直连上游的 $remote_addr:
- 第二层及以内:用
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;(即“上游 XFF + 自己的 $remote_addr”) - 确保最外层已重置,后续层追加才安全;若某一层错误透传原始 XFF,整条链就失效
- 所有代理层都应启用
realip模块,并将上一级代理 IP 加入set_real_ip_from
后端代码必须放弃“兜底逻辑”
常见错误是写类似“先读 XFF,再 fallback 到 REMOTE_ADDR”的代码。这等于给伪造头开了后门:
- Java 应用应统一读
request.getHeader("X-Real-IP")(前提是 Nginx 已设该头) - PHP 中优先用
$_SERVER['HTTP_X_REAL_IP'],而不是$_SERVER['HTTP_X_FORWARDED_FOR'] - ThinkPHP 等框架需严格配置
trust_proxies,只填内网可信段,绝不填公网域名或未验证 IP - 验证是否生效:用 Postman 手动加
X-Forwarded-For: 999.999.999.999,日志中应始终记录真实 IP,而非伪造值











