如何准确获取Yii框架中隐藏在代理后的真实客户端IP地址?
- 内容介绍
- 文章标签
- 相关推荐
本文共计864个文字,预计阅读时间需要4分钟。
这是最常被忽视的安全默认行为:
- 确认你是否用了 Nginx:检查 Nginx 配置里有没有
proxy_set_header X-Real-IP $remote_addr;或proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - 确认云厂商用的头名:腾讯云用
Tencent-Cloud-Real-IP,阿里云 SLB 默认用X-Forwarded-For,AWS ALB 用X-Forwarded-For,但需注意多级代理时该头可能含多个 IP - 必须同时配
ipHeaders和trustedHosts,缺一不可;只加头不设可信段,getUserIP()会直接忽略那些头
正确配置示例(config/web.php):
'request' => [ 'class' => 'yii\web\Request', 'ipHeaders' => ['X-Forwarded-For', 'X-Real-IP', 'Tencent-Cloud-Real-IP'], 'trustedHosts' => ['10.0.0.0/8', '192.168.0.0/16', '172.16.0.0/12'], ],
Yii2 获取真实 IP 的推荐写法:别直接用 userHostAddress
userHostAddress 是只读 REMOTE_ADDR 的快捷属性,完全绕过代理逻辑,等价于裸写 $_SERVER['REMOTE_ADDR']。线上环境务必弃用。
- 统一走
$request->getUserIP(),它会按ipHeaders顺序读头,并校验来源 IP 是否在trustedHosts内 - 如果需要兼容性更强的 fallback(比如某些 CDN 不传标准头),可手动补一层判断:
$ip = $request->getUserIP() ?: $request->getRemoteIP(); -
getRemoteIP()是底层方法,返回未经代理校验的REMOTE_ADDR,仅作兜底,不能当主力
Yii3 使用 PSR-7 ServerRequest 时怎么取真实 IP
Yii3 彻底移除了 getUserIP() 封装,所有逻辑得自己写。自由度高,但出错率也高——没人帮你校验代理是否可信。
- 先读头:
$request->getHeaderLine('X-Forwarded-For')(自动大小写不敏感) - 拆出第一个非私有 IP:
array_filter(array_map('trim', explode(',', $xff))),再逐个用filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)过滤 - 必须手写来源 IP 校验:
$clientIp = $request->getServerParams()['remote_addr'] ?? '127.0.0.1';,然后判断它是否落在你的内网段(如10.0.0.0/8)内,只有可信来源才接受其转发的头 - 别忘了 fallback 到
$clientIp——当所有头都为空或不可信时,这是唯一能用的值
调试 IP 获取失败的三个关键检查点
线上看到 IP 固定为 127.0.0.1、10.x.x.x 或空字符串,基本就卡在这三处。
- Nginx(或 CDN)没转发 IP 头:用
curl -H "X-Real-IP: 1.2.3.4" http://your-site.com/test手动测试头是否透传到底层 PHP -
trustedHosts没覆盖实际代理网段:比如 SLB 实际出口是172.20.10.5,但配置里只写了192.168.0.0/16,那头就被无视了 - PHP 运行模式影响
$_SERVER:FastCGI 下部分头可能被 Nginx 截断或重命名,检查phpinfo()页面里的HTTP_X_REAL_IP是否存在
真实 IP 获取不是“调一个函数就行”的事,它是网络链路、中间件配置、框架安全策略三者对齐的结果。少对一环,拿到的就是假 IP。
本文共计864个文字,预计阅读时间需要4分钟。
这是最常被忽视的安全默认行为:
- 确认你是否用了 Nginx:检查 Nginx 配置里有没有
proxy_set_header X-Real-IP $remote_addr;或proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - 确认云厂商用的头名:腾讯云用
Tencent-Cloud-Real-IP,阿里云 SLB 默认用X-Forwarded-For,AWS ALB 用X-Forwarded-For,但需注意多级代理时该头可能含多个 IP - 必须同时配
ipHeaders和trustedHosts,缺一不可;只加头不设可信段,getUserIP()会直接忽略那些头
正确配置示例(config/web.php):
'request' => [ 'class' => 'yii\web\Request', 'ipHeaders' => ['X-Forwarded-For', 'X-Real-IP', 'Tencent-Cloud-Real-IP'], 'trustedHosts' => ['10.0.0.0/8', '192.168.0.0/16', '172.16.0.0/12'], ],
Yii2 获取真实 IP 的推荐写法:别直接用 userHostAddress
userHostAddress 是只读 REMOTE_ADDR 的快捷属性,完全绕过代理逻辑,等价于裸写 $_SERVER['REMOTE_ADDR']。线上环境务必弃用。
- 统一走
$request->getUserIP(),它会按ipHeaders顺序读头,并校验来源 IP 是否在trustedHosts内 - 如果需要兼容性更强的 fallback(比如某些 CDN 不传标准头),可手动补一层判断:
$ip = $request->getUserIP() ?: $request->getRemoteIP(); -
getRemoteIP()是底层方法,返回未经代理校验的REMOTE_ADDR,仅作兜底,不能当主力
Yii3 使用 PSR-7 ServerRequest 时怎么取真实 IP
Yii3 彻底移除了 getUserIP() 封装,所有逻辑得自己写。自由度高,但出错率也高——没人帮你校验代理是否可信。
- 先读头:
$request->getHeaderLine('X-Forwarded-For')(自动大小写不敏感) - 拆出第一个非私有 IP:
array_filter(array_map('trim', explode(',', $xff))),再逐个用filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)过滤 - 必须手写来源 IP 校验:
$clientIp = $request->getServerParams()['remote_addr'] ?? '127.0.0.1';,然后判断它是否落在你的内网段(如10.0.0.0/8)内,只有可信来源才接受其转发的头 - 别忘了 fallback 到
$clientIp——当所有头都为空或不可信时,这是唯一能用的值
调试 IP 获取失败的三个关键检查点
线上看到 IP 固定为 127.0.0.1、10.x.x.x 或空字符串,基本就卡在这三处。
- Nginx(或 CDN)没转发 IP 头:用
curl -H "X-Real-IP: 1.2.3.4" http://your-site.com/test手动测试头是否透传到底层 PHP -
trustedHosts没覆盖实际代理网段:比如 SLB 实际出口是172.20.10.5,但配置里只写了192.168.0.0/16,那头就被无视了 - PHP 运行模式影响
$_SERVER:FastCGI 下部分头可能被 Nginx 截断或重命名,检查phpinfo()页面里的HTTP_X_REAL_IP是否存在
真实 IP 获取不是“调一个函数就行”的事,它是网络链路、中间件配置、框架安全策略三者对齐的结果。少对一环,拿到的就是假 IP。

