抓鱼鸭&摸鱼聊天室,是我(Pony)月落创办的一款独立开发产品,是一个专注摸鱼的导航网站;

2024年4月以来断断续续收到各种攻击,持续时间达到两个多月,期间采取各种措施进行防御,然而仍然多数时间处于半瘫痪状态;

这篇文章写一下关于我采用的防御措施和开发中遇到的一些安全问题经验分享。
www.zhuayuya.com

序言

文章撰写至7月初;截止目前攻击已经停止,从4月20到现在为止已经是被攻击的第两个半月了,最近一直在观察攻击数据的变化,目前来看攻击已经停止。

这场持续两个多月的攻击真的是闻所未闻,怎么会有人这么闲那,能持续不间断的攻击哪?

由于抓鱼鸭这款产品的使用高峰期是在工作期间使用,所以攻击者也跟上班一样,每天十点准时发起攻击,六点准时收工,偶尔加加班九十点才收工,我也是服了!!!

基本就是cc攻击,平均每小时1000w次左右,偶尔趁我不注意来一次ddos,让我服务器蹦一下,还攻击我的订单系统让正常用户无法正常下单。

技术问题


1.人机校验

抓鱼鸭账号一直是邮箱注册,而且是自建邮局,并不需要像第三方支付接口费用,所以一开始也没有上人机校验,更没有邮箱黑名单,然后接口就被刷了;

有一天突然一个号称是什么投诉部门的人加我,我以为我又犯啥事了哪;

对方跟我说我的网站向他们邮箱发了几十万条验证码,我 tm 当时就懵了,打开后台一看,这家伙用我的邮件接口给各个政府部门邮箱发验证码,加起来有几百万条,所以赶紧加了邮箱白名单,加上了人机校验;

这里特别感谢一下极验对独立开发者的支持,跟极验工作人员说明情况,并且表明使用量并不大后,给予我们免费使用的机会,然后漏洞成功修复。

2.垃圾消息污染

在解决掉邮箱漏洞之后,对方开始了新的漏洞探索;

这次瞄准了摸鱼聊天室,摸鱼聊天室拥有即时通讯功能,使用MQTT驱动,垃圾消息过滤使用了DFA算法 + 敏感词库,属于是特别初级的防御能力,精准度特别低,而且运行效率很差;

由于攻击者一直高并发刷屏,所以后端略显吃力,开始着手解决,发现了另一种比DFA略高效率的敏感词过滤算法AC算法;

这种算法虽然也是词库过滤,但是无论是精准上还是运行效率上都大大提高,攻击者即使使用一些符号来掩饰垃圾信息也会被判定为违规,属于是特别严格的那种;

虽然会误杀一些正常信息,然后配合上koa-ratelimit中间件,做了一个限速,算是暂时防住了。

敏感词过滤用的下边这个库↓↓↓

3.消息发送的漏洞

防住之后对方的茅就又开始乱刺了,继续寻找新漏洞;

它发现了我的MQTT没有鉴权,接收到后直接进行消息转发;

我的消息是通过POST上传的,正常来说你发一条消息,要走我的API接口,后端收到一个POST,然后过滤,储存,再通过MQTT转发出去;

话又说回来了,如果不走我的API直接向MQTT发送消息那?

嗯,没错这就是一个巨大的BUG,由于没有做鉴权,会被MQTT直接广播给所有用户,所以它利用这一漏洞完美绕过了敏感词过滤机制,又开始了新一轮的有效刷屏;

然而这个很好解决,我的MQTT用的是EMQX部署的服务,只需要增加一个ID鉴权就可以解决,它的原理是向MQTT发送消息的时候必须传一个已经被允许的ID才会广播,这样问题就有解决了;

然而事情并没有完,它又发现我的昵称设计还有漏洞;

因为我是产品经理独立开发者,所以没有学过数据库,一直在用sequelize这款ORM查库,它的关联表查询巨抽象,所以在数据库关联表查询这一块就没有研究;

所以在设计获取昵称机制的时候就偷了个懒,在发送消息的时候并不是去用户表使用关联ID查询的用户昵称,而是用户在前端直接发送的昵称,在发送消息的时候并不会校验昵称的合规,所以攻击者干脆就抓接口直接发送违规昵称,照样可以显示出来;

同时还存在一个更严重的漏洞,那就是在发消息的时候,用户ID并没有去校验用户的token,一切都以前端传过来的数据为准,传啥我就广播啥,也就是说它可以顶着任意的ID去发消息,这让我根本无法辨认它到底是谁;

所以我连夜加了token校验,并且连夜学习了关联表的设计,不得不说火烧眉毛的时候学习就是快。

4.后端爆炸

以上问题在得到解决之后就开启了新的征程,依然是基于找漏洞,它突然又发现我的接口没有做数据合法性校验,什么意思哪?

就是比如我的接口用到了user_id,如果没有传这个字段,那么我在接收并使用这个字段的时候ctx.body.user_id,这样取不到东西,我的后端没有捕获错误就会整个崩掉,然后pm2就会自动重启,就这么它脚本空值扫我的接口,我的后端就一直在重启;

于是我抓紧上了一个数据合法性校验的插件joi,这个插件可以在数据不完整或者数据类型错误的时候捕获错误,并直接返回400

随后还加了一个小技巧,在前端写了一段生成token的代码混淆后打包到了vue里;

代码很简单就是排列组合用户当前请求的urluseridtoken,做了一个sha256的加密发给后端,后端取出来之后,用请求头自己拼一下sha256比对一下,对得上就是合法对不上直接返回404,主要是用于迷惑,破解倒不难,尤其是混淆用Ai很容易转成结构化,但是从日志看起来它没有破解掉。

5.上WAF

这么一搞它又没办法了,然后就转成了纯粹的cc攻击,无差别攻击接口,虽然没什么效果但一直打所以很难受,CPU和带宽一直飙的很高,于是我就去找新的防御方法;

到群里一问,很多人推荐雷池WAF,说可以防攻击,我部署了一下,由于他是一种反代理的形式,而且跟宝塔有冲突,所以必须是一台新服务器才能很好的运行;

我找月落借了一台小水管,装上试了一下,结果由于cc太猛了,小水管根本遭不住,雷池直接崩了,然后整个业务也跟着一起寄了(捂脸哭);

其实这个真不怪雷池,WAF属于应用层防御,只要打到这一层代表服务器资源已经被消耗了,能不能打进里边已经无所谓了,所以WAF这东西不配合高配服务器的话针对cc的防御就是个纸老虎。

6.持续性cc

由于WAF的大败溃我的问题又回到了原点,如何防cc攻击哪?

要细究的话,说是cc攻击也不完全是,就是一直在扫,在应用层就被打回了,并没有攻击到我的数据库,但同时也在消耗我的资源,这里nodejs的缺点就显现出来了,单线程,服务器性能不能被完全发挥;

所以我想到了一个骚操作,把入口文件复制多份,在不同的端口运行,用nginx做一个负载均衡,这样就实现了多线程和负载均衡,除了内存占用太高外没别的毛病。

7.反击

这个反击是跟我朋友瓜皮虾交流的时候他想试试能不能用这个思路,我说可以搞,朋友就给它搞了一下,但就成功了一次;

gzip炸弹原理是给它返回一个压缩后只有几 k 的数据包,它程序解压后会变成几十 G,然后它内存就被爆了;

从服务器监控来看明显数据包返回后服务器的资源占用立刻下来了,让对方 cd 了两个小时,但是这下同样也增加了对方的的愤怒值,接着就是更猛烈的攻击,并且它不会再解压返回的数据包;

8.低成本解决方案高防cdn

那如何彻底解决攻击问题那?我找了几个方案;

第一种 是用高防IP做反代理,请求先发送到高防IP那边,可以做规则防御,然后转到业务服务器做业务计算,同时做好负载均衡,想来想去,高防IP成本太高,直接PASS;

第二种 方案就是高防cdn,它可以在cdn层建立规则,把攻击阻挡在业务服务器层之外,就设置了cc频率限制 + ip地区 + 请求头 就防御住了;

最开始用的腾讯云的EdgeOne 9.9一个月够用,但是有的域名没有备案如果用EdgeOne的话未备案必须选境外加速,选了境外之后国内访问只有一条巨慢的线路,所以去淘宝买了个 9.9的香港高防cdn,境内外都可以非常丝滑的访问。

后来蓝易云找到了我,表示可以赞助高防cdn现在切换到了蓝易云稳定性很好,速度也非常快,另外也感谢亚洲云的高防御服务器赞助,非常感谢对抓鱼鸭的赞助。

其实无论做什么防御,核心原理就一个,那就是把攻击挡在业务服务器外,只要设置好规则,攻击被拦截的不算计费流量,就可以解决大部分攻击。

人的问题

说完技术问题再来说一说人的问题;

这次被盯上我也进行了深刻的反思,反思后觉得我的问题比较大,起因很简单,它在我平台上发垃圾小广告,我给它封了就完了,但是我嘴欠骂了它一顿,而且还写了一篇公众号骂,属于是结仇了;

作为官方我不应该这样的,平静对待,封号拉黑完事,官方不要以官方的立场去跟用户对骂,无论是不是真用户,这是我做的不好的地方,吸取教训。

其他经验分享

再说点其他的,被攻击发现了一个很神奇的事情,首先是阿里云和腾讯云,一旦被攻击立马封IP,短则一个小时,长则一天,我查了一下说是被ddos会影响机房线路,对其他服务器造成影响,所以做了攻击熔断机制;

而且阿里云根本不支持换ip,提示说固定套餐不支持换,而之前没有上 cdn,ip 又暴漏了,就眼睁睁的看着被打,没有一点办法,被打废了两台服务器,具体什么攻击不清楚就是部分地区 ping 不通,现在那两台挂了的已经恢复了,足足有一个多月才恢复的;

但是抓鱼鸭的赞助服务商亚洲云稳的一批,几乎抗住了所有攻击;

所以选服务器这东西,真不是服务商越大越好,阿里云腾讯云是大,但跟你有什么关系,不充钱你也不能变强,不如找熟悉的小服务商,关系处好了被攻击说一声,直接从机房层面给你设规则抗一波;

这次复盘就先到这这里吧,攻防这种事任重而道远,最好的防御就是少惹别人,哎!