多层代理 获取真实IP 问题百度一搜 一堆. 但大多都是通过 X-Forwarded-For
获取真实IP
原理就是 负载 LVS
/EOB
/SLB
为了让下游正常获取 客户端IP 会将 客户端IP 填充到 X-Forwarded-For
中传递给下游服务
用户真实IP
, 负载
, 代理服务器1-IP
, 代理服务器2-IP
我们原来获取真实IP 直接就 逗号炸开 取第一个IP
问题来了 客户端请求头 只需要添加 X-Forwarded-For
头信息 就可以伪造IP
解决方案:
- 根据自己服务代理层数决定 层数 != ip 数 就丢包
/**
* @desc 检测异常IP
* @return string
* @throws
*/
public static function checkLimitIp()
{
$header_data = Http::getHeader();
foreach (array('x-real-forwarded-for', 'x-forwarded-for', 'http_x_forwarded_for', 'x-real-ip', 'http_client_ip', 'remote_addr') as $v1) {
if (isset($header_data[$v1])) {
$ip_list = explode(',', $header_data[$v1]);
// todo 注意 前端 slb + nginx IP
$ip_num = count($ip_list);
if ($ip_num > 2) {
throw new ErrorException(-114);
}
}
}
}
- 代理层除了第一层负载外 全部都是内网IP 所以只需要倒着数 找到最后一个外网IP 就可以定位到 负载IP , 负载IP 的前面就是真实客户端IP
真实深坑. 阿里云SLB 如果是覆盖 X-Forwarded-For
, 不是 追加 X-Forwarded-For
就不会存在用户伪造问题. 也许阿里大佬有自己的想法吧 . 但在业务代码中 过滤真心麻烦....