发现
7.24日,收到阿里云短信通知,可用额度欠费,登录阿里云控制台,发现确实额度低于预警线.
感觉不应该余额用这么快,于是去查看明细,发现cdn账单异常.
查看cdn控制台,从2024-7-23 19:00 左右 ,到2024-7-24 23:55 左右,峰值带宽一直稳定在100M左右,总流量在100G左右,明显受到了异常请求:
检索后得知可能是cdn盗刷中招.看了几个类似的经验,一直没明白,盗刷我的cdn消耗网站的cdn费用,对盗刷者有什么好处,虽然不明白,但是不能让他一直这么搞下去,不然月底吃土了.
初次处理
去cdn控制台下载请求日志 , 不得不说阿里云的cdn日志是真的拉,24小时过去了,cdn日志卡在了受盗刷的时间段,只能下载到18:00~19:00 的日志,猜测是由于盗刷导致日志数据量上升,阿里云的任务跑批变慢或者异常了.
只能找人工要cdn日志,尝试看看前几位的ip能否封掉先止损.拿到日志后,使用awk进行去重排序,找到了被盗刷的静态资源 是一张平平无奇的照片
也定位到了前几位异常ip
那就好办了,把ip加入cdn黑名单,睡觉!
二度攻击
本来以为23号晚上处理完就ok了,结果第二天(24号) 19:30 又收到了欠费通知,我懵了.登录cdn控制台,果然流量又异常了
由于日志有延后性,不能立即封禁恶意访问者ip,只能添加cdn流量封顶关闭
这导致cdn被盗刷10分钟后,cdn直接关停,整个博客和小程序变得不可访问.
本以为停服后对方脚本会放过请求失败的站点,于是手动又开启了cdn
不出意外的又出意外了 , 开启后立马被该嘎了的盗刷脚本打挂了..
看来流量封顶只能作为最终兜底策略,盗刷者是有ip池的,在盗刷前就制定了轮换ip防封的方案,道高一尺魔高一丈,我们看来也不能简单的一封了之了.
最后处理
研究一番,决定使用阿里云cdn的远程鉴权,在鉴权服务中提供cdn鉴权接口,cdn接到资源请求时,请求我们的鉴权接口进行鉴权,我们趁机对访问者的ip和uri资源做限流.话不多说,上chatGPT
稍作调整后
public CommonResponse grantCdn(String ip, String uri) {
// 总开关
if (!rateLimitSwitch) {
return new CommonResponse.Builder().buildSuccess();
}
if (uri.equals("/rpc/grantCdn")) {
return new CommonResponse.Builder().buildSuccess();
}
// 检查是否在黑名单中
if (this.isBlacklisted(ip)) {
log.info("该ip已经被拉黑:{}",ip);
throw new CDNException(SystemReturnEnum.FAILED, "该请求存在风险");
}
// 构建Redis的key
String rateLimitKey = RATE_LIMIT_KEY_PREFIX + ip + ":" + uri;
// 使用Redis的原子操作INCRBY来增加计数,并设置过期时间
Long newCount = redisTemplate.opsForValue().increment(rateLimitKey, 1);
if (newCount == 1) {
// 如果是第一次请求,设置key的过期时间为 rateLimitCountWindow s
redisTemplate.expire(rateLimitKey, rateLimitCountWindow, TimeUnit.SECONDS);
} else if (newCount > rateLimitCount) {
// 请求超过限制,将IP加入黑名单
addToBlacklist(ip);
log.info("该ip请求资源已经超限ip:{},uri:{}",ip,uri);
throw new CDNException(SystemReturnEnum.FAILED, "该请求存在风险");
}
return new CommonResponse.Builder().buildSuccess();
}
private void addToBlacklist(String ip) {
String blacklistKey = BLACKLIST_KEY + ip;
redisTemplate.opsForValue().set(blacklistKey, "true", rateLimitBlackWindow, TimeUnit.SECONDS);
}
/**
* 检查IP是否在黑名单中
* @param ip IP地址
* @return true 如果IP在黑名单中,false 否则
*/
public boolean isBlacklisted(String ip) {
// 检查IP是否在黑名单中
String blacklistKey = BLACKLIST_KEY + ip;
return redisTemplate.opsForValue().get(blacklistKey) != null;
}
重新构建部署鉴权中心
在cdn后台配置鉴权接口
2024-7-25 19:00之后, 讲道理脚本小子又该来扫描了
登录cdn控制台,流量呈锯齿状,被限制在600k左右
查看鉴权中心日志
果不其然该噶的盗刷者今天又换ip了 ,不过一抬头就被按进小黑屋了,关一会又释放出来,然后又被关进去 ... 所以流量呈锯齿状
拿到小黑屋中的ip后,登录到cdn,将他加到cdn的大黑屋中 ,这样就能进一步节省鉴权中心的请求资源
就这样吧 ,在这次盗刷行动中损失了一些元子 ,也对cdn的一些机制有点了解,算是花钱买教训吧~也希望有更好解决方案(买高防除外 ,没有元子..)的童鞋带带
评论区