正确解析x-forwarded-for需从右向左遍历ip列表,排除可信代理及内网ip后取第一个有效ip,而非简单取首或尾;同时须结合代理拓扑、可信边界校验与源ip交叉验证。

直接看日志里的 $http_x_forwarded_for 字段本身不能直接得出“真实源IP”,它只是一串逗号分隔的 IP 列表,必须结合代理拓扑和可信边界做判断。关键不是记录什么,而是**怎么解析、谁加的、谁可信**。
先确认 X-Forwarded-For 是谁添加的
这个头必须由你完全控制的最后一跳代理(如 Nginx、CLB、自建 CDN 回源节点)统一注入,前端不能由客户端或不可信中间件提交:
- 在 Apache 或应用层配置中,建议用
RequestHeader unset X-Forwarded-For early清除原始请求头 - 由可信代理(比如 Nginx)用
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;追加——它会保留原有值再加自身 IP - 若上游是阿里云 CLB 或 AWS ALB,它们默认开启 X-Forwarded-For 插入,无需后端再加,但需确保没被其他代理重复添加
日志中记录完整 XFF 字符串供回溯审计
不要只记一个 IP,保留原始链路信息才能事后排查伪造或异常路径:
- Nginx 日志格式中显式包含
$http_x_forwarded_for,例如:
log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"'; - Apache 中用
%{X-Forwarded-For}i记录整串值,配合%h(代理直连 IP)一起写入,便于比对层级关系 - 示例日志片段:
172.16.0.5 - - [25/May/2026:23:12:04 +0800] "GET /api/login HTTP/1.1" 200 142 "-" "Mozilla/5.0" "203.0.113.45, 198.51.100.22, 172.16.0.5"
从 XFF 中安全提取真实客户端 IP
不能无条件取第一个,也不能取最后一个;要按“可信代理白名单”从右往左跳过已知内网/可控代理,取第一个不匹配的 IP:
- Nginx 推荐用
set_real_ip_from+real_ip_header X-Forwarded-For+real_ip_recursive on,配置后$realip_remote_addr就是还原结果 - Apache 推荐启用
mod_remoteip,配RemoteIPInternalProxy(只填你自己的代理网段),之后%a即为可信首 IP - 手动解析(不推荐):逆序遍历 XFF 列表,排除所有在
10.0.0.0/8、172.16.0.0/12、192.168.0.0/16、127.0.0.1等私有网段的 IP,第一个剩下的就是候选真实 IP
配合源 IP 做交叉验证防绕过
攻击者可能绕过代理直连你的服务器,此时 $remote_addr 反而是真实 IP:
- 在防火墙或安全组中限制仅允许可信代理 IP(如 CLB、CDN 回源段)访问 Web 服务端口,堵住直连入口
- 日志中同时记录
$remote_addr和$http_x_forwarded_for,当两者一致且不在可信代理段时,说明可能被绕过 - 发现扫描行为时,优先查
$http_x_forwarded_for最左 IP;若该字段为空或格式异常(如含非法字符、多个连续逗号),再查$remote_addr










