代理转发真实IP处理错误,业务拿不到真实攻击IP无法封禁
网站通过 Nginx、CDN 或其他反向代理转发请求后,如果后端业务日志里只看到代理服务器的 IP,而看不到用户真实 IP,防火墙就无法封禁攻击来源。
这个问题的根源通常是代理层没有正确传递 X-Forwarded-For 或 X-Real-IP 请求头,而后台也没有配置可信代理列表去读取这些头。
下面按排查顺序讲清楚,配置后你就能重新拿到真实攻击 IP。
先确认代理链路里哪一层丢了 IP
登录服务器后,先用一条测试请求看当前实际透传情况。
在命令行执行:
curl -I http://你的域名/test
然后在 Nginx 访问日志里查看对应记录的 IP。
如果日志里全是代理节点的 IP(比如 127.0.0.1 或 CDN 节点 IP),说明代理层或后端配置有问题。
接着确认你的架构:请求是经过 CDN → Nginx → PHP/Java 应用,还是只有一层 Nginx 反代。
每一层代理都需要向后继续传递原始请求头,任何一个环节漏配都会导致最终拿不到真实 IP。
修复 Nginx 反代的真实 IP 透传
在反向代理的 location 或 server 块中,把下面的配置加进去:
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
$proxy_add_x_forwarded_for 会自动把当前连接 IP 追加到已有 X-Forwarded-For 后面,适合单层代理。
如果是多层代理,建议手动拼接:
set $real_ip $remote_addr;
if ($http_x_forwarded_for) {
set $real_ip $http_x_forwarded_for;
}
proxy_set_header X-Forwarded-For $real_ip;
改完执行 nginx -t 检查语法,再 systemctl reload nginx 让它生效。
后端应用也要信任代理头
很多情况下 Nginx 已经传对了,但 PHP(如 $_SERVER['REMOTE_ADDR'])或 Java 仍然读的是套接字地址。
以 PHP-FPM 为例,需要修改 nginx.conf 里的 fastcgi 参数:
fastcgi_param REMOTE_ADDR $http_x_forwarded_for;
fastcgi_param HTTP_X_REAL_IP $http_x_real_ip;
Apache 用户则启用 mod_remoteip,然后在配置里指定可信代理 IP:
RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy 你的代理服务器IP
注意:不能盲目信任任意传入的 X-Forwarded-For 头,否则攻击者可以伪造。
必须在反向代理层用 set_real_ip_from 限定只有你信任的代理(比如 CDN 回源 IP 段)可以修改这个头。
验证真实 IP 是否已透传
配置完成后,用下面命令模拟请求并观察日志:
curl -H "X-Forwarded-For: 1.2.3.4" -I http://你的域名/test
然后看后端日志。
如果日志记录的是 1.2.3.4,说明透传成功。
这时候在防火墙里封禁这个测试 IP 就可以生效:
iptables -A INPUT -s 1.2.3.4 -j DROP
生产环境建议结合 fail2ban 读取应用日志自动封禁,不用每次手动处理。
避坑和常见疑问
多层代理时只用 X-Forwarded-For 可能被伪造。 正确做法是记录最右边第一个非可信代理 IP,或者让 CDN 厂商在回源时覆盖 X-Forwarded-For 头。
改完配置后不生效? 先检查代理层是否真的 reload,再确认后端是否读取了正确的变量。
PHP 里 $_SERVER['REMOTE_ADDR'] 可能因为 FPM 缓存需要重启生效。
CDN 场景下如何配置? 在 CDN 控制台开启“回源带头”,并让 CDN 把 X-Real-IP 设置为客户端 IP;
后端 Nginx 再用 set_real_ip_from 信任 CDN 节点 IP 段,防止伪造。
完成以上步骤后,你的业务日志就能拿到真实攻击 IP,封禁操作会立刻变得准确。
建议结合访问日志和防火墙工具建立自动封禁流程,避免每一次攻击都靠手工处理。