[EdgeOne盗刷复盘] 设置防盗刷规则与针对盗刷IP进行Gzip炸弹或黑洞反击

前段时间出现了大规模的CDN盗刷,我也没能逃过被刷了200G。

今天来复盘一下被刷过程,以及应对方法。

现象与分析

本次盗刷有三个特征,特定的IP、特定的路径和短时间大量请求。

在上图中出现了两个访问高峰,分别对应两个IP,在6号和7号18点到19点大量盗刷流量。

单独取出一次高峰来看,请求速率很高,一张300K的图片在5分钟内产生了3-5G的流量。

为何拦截未生效

因为我没有设置拦截。

EdgeOne按干净流量计费的卖点 吸引了不少用户前来购买。

但值得注意的是,因为不同用户的场景不同,EdgeOne附带默认的设置项不多,而是给用户更多的自定义空间。

许多新用户购买后添加网站后直接就开始用,并没有去做安全相关的设置(例如我),也就导致了盗刷的发生。

如何设置拦截

根据第一节的分析可以得出拦截的对策如下:

  1. 设置用量封顶,避免出现像我那样分两天被刷了200G才发现。
  2. 单IP频次限制,设置合适的频次限制,筛选出盗刷IP并冻结。
  3. (可选)开启Bot识别,通过浏览器指纹识别出盗刷者。

这里要讲一下2和3。把3列为可选是因为他是增值服务,需要额外付费。

但是在预算充足的情况下建议用3代替2。

因为目前国内绝大多数家宽不是一户一个公网IP,而是一群人公用一个公网IP通过NAT上网。

当一个公网IP共用的人太多,而他们又打开了你的网站,有可能会碰到阈值被封禁。还有当盗刷者因为盗刷被封禁时,也会连累同IP下其他用户使其无法访问。

换到3就不同了,它会根据请求分析是否属于盗刷,并把盗刷的请求拦截下来。

换句话说,2的方法更简单粗暴,只要你请求数太多,不管你是不是正常请求一律封禁,而3会根据请求分辨出哪些是正常访问那些是异常访问。

设置方法

用量封顶

进入待设置的站点,找到用量封顶策略,新建一条策略

这里根据你的实际情况做设置,我设置的是每日流量的10倍,用来给频次限制兜底。

当你的网站达到告警阈值,会收到阈值提醒,如下:

当你的网站达到封顶值时,会收到停用提醒,如下:

频次限制

ps.这个需要EO标准版才支持

用量封顶策略往上,有一个安全防护,进去之后找到Web防护 >> 精准速率限制,新建一条规则

注意不是上面的自适应频控,上面的是防CC的,虽然也在速率限制这一大项内但不是它,如下是工单的回复:

回到正题,点击新建规则后会有一个弹窗,选择空白模板,起个名字:

在右侧的弹窗进行设置。

有一点要注意,请求域名在输入你自己的域名后要按一下回车才生效。

一般情况下,因为网页会引用诸如CSS/JS、图片、字体等外部资源,所以打开一个网页不是只有一个请求,而是会有多个请求,所以这里需要根据你的实际情况做设置。

例如我的网页平均一个网页会有6个请求,这里设置的120意味着在10秒内同一个IP下能让20人访问我的网站。

点击保存并发布后,即可在页面上看到这条规则:

关于反制的思考

Gzip炸弹

为了节省流量,不少网站会采用Gzip对网页信息做压缩,在客户端再解压,在绝大多数的浏览器与编程语言的请求库里这个过程是自动的。

根据压缩的原理,可以设计出一个解压大小是其本身数百倍的压缩包。

当客户端收到这种压缩包并尝试解压时,如果机器资源不足可以迅速吃光机器资源并把程序搞崩掉。

精准速率限制中,处置方式除了拦截还可以设置为重定向。

通过这个功能,可以把盗刷者重定向到搭建好的Gzip炸弹路径。

搭建起来也不难,先生成一个Gzip包,解压后大小为1G,压缩后大小为1M:

代码语言:javascript
复制
dd if=/dev/zero bs=1M count=1024 | gzip > test.gzip

10G用这个:

代码语言:javascript
复制
dd if=/dev/zero bs=1M count=10240 | gzip > test.gzip

然后使用Flask编写一个程序,把这个包作为载荷返回:

代码语言:javascript
复制
from flask import Flask, Response

app = Flask(name)

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def send_gzip_bomb(path):

with open(r&#39;test.gzip&#39;, &#39;rb&#39;) as payload_gzip:
    resp = payload_gzip.read()
final_response = Response(response=resp, status=200, mimetype=&#39;text/html&#39;)
final_response.headers[&#39;Content-Encoding&#39;] = &#39;gzip&#39;
return final_response

if name == 'main':
app.run(host='0.0.0.0', port=5432)

效果如图:

采集盗刷IP并将其拉入黑洞

EddgeOne可以通过设置实时日志,将防护日志发往指定接收API

在日志中,会包含客户端来源IP的字段

在API端筛选出盗刷IP,再自动调用某些妙妙工具,即可将盗刷IP拉入黑洞。