• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

Laravel框架中-getClientIps-原理和用法

php 搞代码 3年前 (2022-03-01) 40次浏览 已收录 0个评论
文章目录[隐藏]

起因是用 $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…


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:Laravel框架中-getClientIps-原理和用法

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址