前段时间出现了大规模的CDN盗刷,我也没能逃过被刷了200G。
今天来复盘一下被刷过程,以及应对方法。
现象与分析
本次盗刷有三个特征,特定的IP、特定的路径和短时间大量请求。
在上图中出现了两个访问高峰,分别对应两个IP,在6号和7号18点到19点大量盗刷流量。
单独取出一次高峰来看,请求速率很高,一张300K的图片在5分钟内产生了3-5G的流量。
为何拦截未生效
因为我没有设置拦截。
EdgeOne按干净流量计费的卖点 吸引了不少用户前来购买。
但值得注意的是,因为不同用户的场景不同,EdgeOne附带默认的设置项不多,而是给用户更多的自定义空间。
许多新用户购买后添加网站后直接就开始用,并没有去做安全相关的设置(例如我),也就导致了盗刷的发生。
如何设置拦截
根据第一节的分析可以得出拦截的对策如下:
- 设置用量封顶,避免出现像我那样分两天被刷了200G才发现。
- 单IP频次限制,设置合适的频次限制,筛选出盗刷IP并冻结。
- (可选)开启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:
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)
效果如图:
采集盗刷IP并将其拉入黑洞
EddgeOne可以通过设置实时日志,将防护日志发往指定接收API
在日志中,会包含客户端来源IP的字段
在API端筛选出盗刷IP,再自动调用某些妙妙工具,即可将盗刷IP拉入黑洞。
1 条评论
你可以使用这个黑名单列表,效果非常好
https://github.com/unclemcz/ban-pcdn-ip
也可以使用我进行Fork和维护的精简列表
https://github.com/LeterTW/CDNAbuseTracker