webman读不到真实ip的根本原因是nginx未透传或未校验可信代理来源;必须配置proxy_set_header x-real-ip $remote_addr等头,并在webman中校验$_server['remote_addr']是否属于可信代理网段后,才安全读取http_x_real_ip或http_x_forwarded_for首ip。

Webman 里拿不到真实 IP,不是 PHP 读错了,而是 Nginx 没传、或传了但没校验来源——直接读 $_SERVER['REMOTE_ADDR'] 在有代理时永远是错的。
Webman 为什么读不到真实 IP
Webman 默认不解析任何 HTTP 头,它和原生 PHP 一样,$_SERVER['REMOTE_ADDR'] 只反映 TCP 连接对端(比如 Nginx 的内网 IP),不是用户出口 IP。常见现象包括:
- 所有请求的
$_SERVER['REMOTE_ADDR']都是127.0.0.1或10.x.x.x - 日志里 IP 高度集中,但实际访问来源分散
- 用
$_SERVER['HTTP_X_FORWARDED_FOR']直接取值,结果被curl -H "X-Forwarded-For: 1.2.3.4"轻松绕过
根本原因:没有可信代理链 + 没做来源校验。Webman 不会自动帮你判断哪个头可信,得你自己写逻辑。
Nginx 必须配置 proxy_set_header 才能透传
Webman 是常驻进程,不重启,所以依赖 Nginx 主动把真实 IP 塞进请求头。缺一不可:
-
proxy_set_header X-Real-IP $remote_addr;—— 最干净,只传当前直连 IP(即用户或上一级可信代理) -
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;—— 更安全,继承旧值再追加,避免覆盖原始链路 -
proxy_set_header Host $host;—— 防止后端因 Host 错乱导致 HTTPS 判断失败或重定向异常
注意:$proxy_add_x_forwarded_for 和 $remote_addr 不等价;前者保留历史,后者只是“这一跳”的 IP。
Webman 中安全读取真实 IP 的代码逻辑
不能无脑 fallback,必须先校验 $_SERVER['REMOTE_ADDR'] 是否来自你信任的代理网段,再决定读哪个头:
- 定义可信代理列表,例如:
$trustedProxies = ['127.0.0.1', '10.0.0.0/8', '172.16.0.0/12']; - 用
ip_in_range($_SERVER['REMOTE_ADDR'], $trustedProxies)判断是否可信(别用===简单匹配 CIDR) - 可信时才依次检查:
$_SERVER['HTTP_X_REAL_IP']→$_SERVER['HTTP_X_FORWARDED_FOR'](取explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0]后trim()) - 每个候选 IP 都要过
filter_var($ip, FILTER_VALIDATE_IP),并排除私有地址(127.0.0.0/8、10.0.0.0/8、192.168.0.0/16、172.16.0.0/12)
示例片段(可放 app/Bootstrap.php 或中间件中):
function getRealIp(): string
{
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
$trustedProxies = ['127.0.0.1', '10.0.0.0/8'];
if (ip_in_range($ip, $trustedProxies)) {
if (!empty($_SERVER['HTTP_X_REAL_IP'])) {
$ip = $_SERVER['HTTP_X_REAL_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ips = array_map('trim', explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']));
$ip = $ips[0] ?? $ip;
}
}
return filter_var($ip, FILTER_VALIDATE_IP) ? $ip : '0.0.0.0';
}
Cloudflare 或阿里云 SLB 等第三方代理怎么处理
它们不会设 X-Real-IP,但会设自己的头,且格式固定:
- Cloudflare:
$_SERVER['HTTP_CF_CONNECTING_IP']—— 只在开启 CF 且未被中间层覆盖时有效,无需解析,直接校验合法性 - 阿里云 SLB / ALB:
$_SERVER['HTTP_X_FORWARDED_FOR']可能已含真实 IP,但必须确认其回源段(如100.64.0.0/10)已加入$trustedProxies - 腾讯云 CLB:
$_SERVER['HTTP_X_REAL_IP']有时可用,但不如HTTP_X_FORWARDED_FOR稳定,仍需白名单校验
重点:第三方代理的头不能跳过来源校验。哪怕 Cloudflare 的 CF-Connecting-IP 很可靠,如果请求是经你自己的 Nginx 再转发一次,而 Nginx 没配 set_real_ip_from,那这个头就可能被污染。
最易被忽略的一点:Webman 启动后不 reload 配置,$_SERVER 是 PHP-FPM 或 CLI 启动时快照的,所以 Nginx 改了 header,Webman 进程必须重启才能生效;开发时容易误以为逻辑没跑通,其实是进程没更新上下文。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











