多层反向代理下ip访问控制失效的根本原因是真实客户端ip在转发链中被覆盖或丢失,导致策略作用于错误ip;需逐跳验证x-forwarded-for透传完整性、正确配置proxy_set_header与real_ip指令、后端读取可信ip而非remote_addr,并实测策略生效性。

多层反向代理下 IP 访问控制失效,核心问题不是规则写错了,而是真实客户端 IP 在转发链中被覆盖或丢失,导致 allow/deny、限流、白名单等策略全部作用在错误的 IP 上(比如全是内网地址或 CDN 回源 IP)。排查关键在于逐跳验证 IP 透传是否完整、可信。
确认最外层入口是否真正传递了真实 IP
这是整个链条的起点。如果第一跳代理(如 Cloudflare、AWS ALB、Nginx 网关)没把用户真实 IP 放进请求头,后面所有环节都无从谈起。
- 检查上游是否设置
X-Forwarded-For:对 HTTP 代理,必须有proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;;对 HTTPS 四层代理(如启用 Proxy Protocol),则需后端 Nginx 配置set_real_ip_from+real_ip_header proxy_protocol - Cloudflare 用户要额外配置信任段和头字段:
set_real_ip_from 173.245.48.0/20;等(以官方最新段为准),real_ip_header CF-Connecting-IP; - 用 curl 直接访问最外层入口,加
-v查看响应头里是否有X-Forwarded-For: 客户端真实IP, ...,且第一个 IP 是你预期的公网地址
验证中间每一层是否正确继承并追加 X-Forwarded-For
中间代理若直接覆盖而非追加该头,会导致原始 IP 被丢弃。常见错误是用了 $remote_addr 而非 $proxy_add_x_forwarded_for。
- 在每一层 Nginx 的
location或upstream块中,确认proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;—— 注意是_add_,不是$http_x_forwarded_for或$remote_addr - HAProxy 需开启
option forwardfor;Envoy 需启用xff_num_trusted_hops并设为实际跳数 - 用日志临时记录每层收到的
$http_x_forwarded_for值,对比前后是否连续、是否被截断或替换成单一内网 IP
检查最终应用层是否基于真实 IP 做判断
即使头传到了,如果后端服务仍读 REMOTE_ADDR(即 $remote_addr),就等于没用。必须让业务逻辑读取解析后的可信 IP。
- Nginx 中通过
map提取真实 IP:map $http_x_forwarded_for $real_client_ip {<br> ~^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) $1;<br> default $remote_addr;<br>}
再在allow/deny或限流中使用$real_client_ip - PHP 应用需读
$_SERVER['HTTP_X_FORWARDED_FOR']并取最左有效 IP,不能直接用$_SERVER['REMOTE_ADDR'] - Java Spring Boot 可配
server.forward-headers-strategy=framework,并确保trusted-proxies列出所有上游可信代理网段
验证访问控制策略是否生效在真实 IP 上
光配置对还不够,得实测。用不同来源 IP(手机热点、家庭宽带、公司出口)发起请求,观察日志中匹配的 IP 是否与你预期一致。
- 在 Nginx access_log 中加入
$real_client_ip字段,确认日志里出现的是真实公网 IP,而非 10.x、172.x、192.168.x - 临时加一条
deny 1.2.3.4;(用一个已知测试 IP),然后从该 IP 请求,看是否返回 403;再换其他 IP 测试是否放行 - 若用第三方 WAF 或云防火墙,检查其“可信代理 IP 段”是否填全了所有中间节点的出口网段,否则它会把最后一跳当作真实 IP











