乐趣区

关于php:Laravel框架中-getClientIps-原理和用法

起因是用 $request->ip() 来获取 ip 限流,忽然受到大面积误杀。排查 access.log 日志,简直所有申请的 $remote_addr,都为某几个固定 ip。征询运维后发现是他轻轻给前端加了 cdn。那为何会产生这种问题呢?

remote_addr 和 http_x_forwarded_for

先来理解一下前置常识。

remote_addr 是实在的与 Web 服务建设连贯的 ip。在不通过代理服务器的时候,能获取到用户实在 IP,不可伪造

但少数申请都通过反向代理、CDN 减速等服务,再达到 Web 服务。这时候与 Web 服务实在建设连贯的就是代理服务器。相应地 remote_addr 的值也变成了代理服务器的 ip。那么通过代理服务器的服务,如何能力获取到用户实在 IP 呢?

X-Forwarded-For 则应运而生。它是一个 HTTP 扩大头部,用来记录一个申请路径服务器的 ip,能够了解为一个 ip 链条。每路径一台代理服务器,它会把访问者的 ip,追加到 X-Forwarded-For 中。

但 X-Forwarded-For 是 能够伪造 的,客户端可能从最后收回的申请中 X-Forwarded-For 就携带者几个 ip。

格局如下:

X-Forwarded-For:client_ip, proxy1_ip, proxy2_ip

Laravel 获取 ip

Symfony 的 Request 类中这样实现 getClientIps()

public function getClientIps()
{$ip = $this->server->get('REMOTE_ADDR');

    if (!$this->isFromTrustedProxy()) {return [$ip];
    }

    return $this->getTrustedValues(self::HEADER_X_FORWARDED_FOR, $ip) ?: [$ip];
}

首先,从 REMOTE_ADDR 中获取了与 Web 服务建设实在连贯的客户端 ip。而后,判断此 ip 是否是受信赖的代理,如果不是则间接返回此 ip。最初,调用 getTrustedValues() 来获取和解决 X-Forwarded-For。

(因为 Laravel 默认是受信赖代理是空,所以导致了开篇提到的问题,如何设置信赖代理见下文)

getTrustedValues() 次要有两个引入瞩目的操作:

  1. 如果 X-Forwarded-For 的 ip 链条中,也存在受信赖的代理 ip,会被过滤。
  2. 将过滤后的 ip 链条 反转 返回;如果过滤后的 ip 链条 为空,则返回受信赖的代理 ip。

getClientIps() 返回 ip 链接条,与 X-Forwarded-For 程序相同,这时常会让开发者踩坑。那为什么会这么设计呢?

Symfony 开发者在正文中是这么解释的:

返回的数组中,最受信赖的 ip 排在第一位,最不受信赖的 ip 排在最初一位。“实在”的客户端 ip 排在最初一位,但它也是最不受信赖的。受信赖的代理 ip 已被从中移除。

看完你会豁然开朗。

如何食用

如果,一个申请如下:

client->proxy1->proxy2->proxy3->web service

proxy1-3 是咱们的代理服务器

那么,它的 X-Forwarded-For:client_ip, p1_ip, p2_ip

因为,proxy1-3 是咱们的代理服务器是可信的。

咱们将 p1_ip, p2_ip, p3_ip 退出受信赖代理。

namespace App\Http\Middleware;
……
class TrustProxies extends Middleware
{
    protected $proxies = [p1_ip, p2_ip, p3_ip];

……

那么,getClientIps() 会返回

[client_ip]

因为,client_ip 是由 proxy1 代理服务器追加到 X-Forwarded-For,所以是可信的,可作为用户的实在 IP。

如果,客户端申请前 X-Forwarded-For 就已有一个 ip(client0_ip)

getClientIps() 会返回

// 信任度从高到底
[
    client_ip,
    client0_ip
]

client0 有可能是用户实在的 ip,也有可能是本人伪造的 X-Forwarded-For,并不能信赖它。

参考文章

https://www.cnblogs.com/lcawe…

https://learnku.com/articles/…

PS: 写完后,发现一篇写的很棒的文章 https://segmentfault.com/a/11…

退出移动版