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

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

现象与分析

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

1722793717803.jpg

1722793730097.jpg

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

1722793741327.jpg

单独取出一次高峰来看,请求速率很高,一张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倍,用来给频次限制兜底。

1722793767753.jpg

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

1722793780521.jpg

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

1722793799409.jpg

频次限制

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

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

1722793812163.jpg

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

1722793838871.jpg

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

1722793823964.jpg

在右侧的弹窗进行设置。

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

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

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

1722793852715.jpg

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

1722793866582.jpg

效果

设置规则几天后,来补一下拦截的效果:

1723676373360.png

效果还是挺不错的,在拦截生效后,盗刷方发现刷不动了开始放弃了。

放弃几天后开始又开始尝试盗刷,都成功拦截了。

1723676634690.png

关于反制的思考

Gzip炸弹

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

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

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

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

1722793919257.jpg

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

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

dd if=/dev/zero bs=1M count=1024 | gzip > test.gzip

10G用这个:

dd if=/dev/zero bs=1M count=10240 | gzip > test.gzip

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

from flask import Flask, Response

app = Flask(__name__)


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

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


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5432)

效果如图:

1722795803519.png

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

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

1722793935393.jpg

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

1722793946830.jpg

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

最后修改:2024 年 08 月 15 日
如果觉得我的文章对你有用,请随意赞赏