不能靠X-Forwarded-For防伪造,必须由最外层Nginx用$remote_addr覆盖该头,中间层仅追加,后端只读X-Real-IP或严格校验XFF首IP,同时启用real_ip_module并禁用危险头透传。

不能靠 X-Forwarded-For 自己防伪造,它天生可被任意篡改;真正有效的做法是用 Nginx 主动控制这个头的生成逻辑,把“谁有权写、怎么写、写什么”全部收归可信链路——核心是让最外层代理用真实连接 IP 覆盖该头,后续层只追加、不采信,后端只认这个链路产出的结果。
第一层必须重置 X-Forwarded-For
当 Nginx 直接面向公网(比如接 CDN 或 WAF),它收到的 $remote_addr 就是真实客户端 IP 或可信上游代理 IP。此时必须丢弃客户端可能带的所有 X-Forwarded-For 值,强制设为:
- proxy_set_header X-Forwarded-For $remote_addr;
- proxy_set_header X-Real-IP $remote_addr;
- 禁用 $proxy_add_x_forwarded_for——它会拼接原始请求头,引入伪造风险
中间层只追加、不还原
如果架构中有多个 Nginx 层(如 CDN → 接入层 Nginx → 业务层 Nginx → 后端服务),第二层及以内不能重新解析或信任上游传来的 X-Forwarded-For 值,只需把当前直连上游的 IP 追加到链尾:
- 配置 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- 这个变量含义是:“上游传来的 XFF 值 + , + 当前 $remote_addr”
- 这样形成的链形结构如:1.2.3.4, 10.1.1.1, 10.2.2.2,最左才是真实客户端 IP
后端必须只读可信字段
后端代码绝不能写“优先读 X-Forwarded-For,没值再 fallback 到 RemoteAddr”这种宽松逻辑——那等于给伪造头开了后门。正确做法是:
- 优先读 X-Real-IP 头(由最外层 Nginx 设置,不可伪造)
- 或严格校验 X-Forwarded-For:只取逗号分隔后的第一个 IP,且确认该请求确实来自可信代理(比如检查请求来源 IP 是否在白名单内)
- Java 示例:request.getHeader("X-Real-IP"),不是 getHeader("X-Forwarded-For") 或 getRemoteAddr()
配套加固不能少
单靠 X-Forwarded-For 控制还不够,需同步堵住其他常见绕过点:
- Host 头禁用透传:proxy_set_header Host $proxy_host;,而不是 $host 或 $http_host
- 清除危险响应头:proxy_hide_header Server;、proxy_hide_header X-Powered-By;
- 启用 real_ip_module 并声明可信段:set_real_ip_from 192.168.0.0/16; 等,确保 $remote_addr 在日志和条件判断中已是真实 IP


















