问题:
用Laravel的$request->getClientIp()方法获取IP,
本机nginx proxy 获取到的是docker网络的Ip地址,类似172.17.0.1之流(docker创建的网络,本机的IP不是127.0.0.1)
另外一台机器用nginx proxy 获取到的是机器本身的外网IP
都无法获取客户的真实访问IP
原因:
查看laravel的getClientIp方法源码
public function getClientIps()
{
$clientIps = array();
$ip = $this->server->get('REMOTE_ADDR');
if (!$this->isFromTrustedProxy()) {
return array($ip);
}
$hasTrustedForwardedHeader = self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED]);
$hasTrustedClientIpHeader = self::$trustedHeaders[self::HEADER_CLIENT_IP] && $this->headers->has(self::$trustedHeaders[self::HEADER_CLIENT_IP]);
if ($hasTrustedForwardedHeader) {
$forwardedHeader = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
preg_match_all('{(for)=("?\[?)([a-z0-9\.:_\-/]*)}', $forwardedHeader, $matches);
$forwardedClientIps = $matches[3];
$forwardedClientIps = $this->normalizeAndFilterClientIps($forwardedClientIps, $ip);
$clientIps = $forwardedClientIps;
}
if ($hasTrustedClientIpHeader) {
$xForwardedForClientIps = array_map('trim', explode(',', $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_IP])));
$xForwardedForClientIps = $this->normalizeAndFilterClientIps($xForwardedForClientIps, $ip);
$clientIps = $xForwardedForClientIps;
}
if ($hasTrustedForwardedHeader && $hasTrustedClientIpHeader && $forwardedClientIps !== $xForwardedForClientIps) {
throw new ConflictingHeadersException('The request has both a trusted Forwarded header and a trusted Client IP header, conflicting with each other with regards to the originating IP addresses of the request. This is the result of a misconfiguration. You should either configure your proxy only to send one of these headers, or configure Symfony to distrust one of them.');
}
if (!$hasTrustedForwardedHeader && !$hasTrustedClientIpHeader) {
return $this->normalizeAndFilterClientIps(array(), $ip);
}
return $clientIps;
}
1. remote_addr的值在经过proxy后变成了进行proxy的机器的ip,不再是客户真实的ip了;
2. isFromTrustedProxy判断了proxy的remote_addr,要把remote_addr写入白名单;
3. 经过proxy的ip获取的是X-Forwarded-For的值;
解决办法:
- nginx设置X-Forwarded-For
server {
listen 80;
server_name www.XXXXX.cn;
location / {
proxy_pass http://XX.XX.XX.XX;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
- laravel添加TrustedProxy
通过Request::setTrustedProxies()方法设置;传入ip数组
可以是掩码的格式,例如:
[
"172.17.0.1/16",
"156.132.44.23"
]