记一次线上被灌水攻击

被水军攻击是从7月5日0点43分(最早的帖子)开始的,就是周日的晚上,我是第二天早上知道的,平时就有水军在不停的灌,也不是太在意,下午的时候,监控的人说实在太多了,封不尽删不完,已经处于放弃治疗的状态,但是在休假,电脑也不在身边,有心无力,好几个月了,我只请一天假,攻击就在我请假的时候发动了,有点隆美尔的感觉。

周二刚下火车,来到公司,就开始梳理。实际上,新接手论坛才一两个星期,还要兼顾娱乐频道,代码又丑又乱,对发帖的流程只是大概清楚,虽然自己是技术,负责这个,实际上,也是头大。

先和老大沟通,问具体的情况,了解多少账号,了解发了多少帖子,各个频道的编辑在应对的时候都是怎么做的,请教了可能的应对的方案,然后和监控谈谈,听监控说说概括,看监控有什么主意,然后和各个频道(育儿,星座,科技)谈谈,听他们认为什么方案行之有效,然后连系统,看写入速度,看垃圾用户发帖量,看sso,用户来源,估了下总量。问了一圈,代码层面还是没有什么进展,对如何解决多少有了点谱。

因为了解到主要是有两三千个账号在灌垃圾,只要限制每个账号的每天发帖量,就会极大程度的减小垃圾的量,我依稀记得论坛里面好像是有这个限制的,只是不知道为什么失效了,从数据库里面select 数据来看,有一个垃圾账号一天发了两千多,和监控以及老大碰了下,决定先上这个,然后就是在那堆恶心的代码里面,根据寥寥可数的注释,变量的命名以及从逻辑上连蒙带猜,找到了疑似发帖限制的,我开始以为是时间太久了,mc 挂了,所以导致了限制无效,就不断向就去排查mc 的情况,mc是对的,从最上层一直追查到new Memcache,发现mc是没有问题的。带着失望回头看,无意中发现之前设置的mc的值失效了,这点很神奇,理论上应该是一天后才失效的才对,一行行扫,发现是set的时候,没有指定失效的时间,追查的框架的最底层,也没有发现一个默认的时间,“低级错误………..”,一阵恶心略过心头,加上失效时间之后,测试,发现可以了,赶快上线,略出一口气,应该不会再被大规模灌了,虽然不知道全量垃圾用户多少。

之后要加图片验证码,实际上,我都没有在论坛见过验证码这东西,只是凭借着相信肯定有这么一个东西,就在代码里面扒,看来看去,觉得有一个$secodecheck 的变量,好像是控制这个的开关,有一段代码,看起来像是生成验证码的,但是discuz恶心的地方就是一个.php文件,可以被各种url,以各种不同的参数访问进来,完全不知道怎么让程序运行到这段疑似代码,同一个变量,被穿插在700行没有函数隔离的代码中,在不同地方以各种不同的条件设置置位,不知道为什么这么做,没个解释,有些变量,来自include的子文件,有些变量是全局的,request,get,cookie中的变量也被提出来成为php的变量,变量之间互相污染,防不胜防,后来听说军事论坛有图片验证码,赶快拿来url看看,总算看着url中最初的变量,以及连蒙带猜,加上几分运气经验,在下班前将图片验证码上线了,防住了水军的继续灌。上面的这些事情加起来就消耗了一天的时间。

之后开始按照频道的要求开始清除这段时间的垃圾内容,我开始以为会很简单,但是却花了整整一天。因为对论坛删除帖子的过程不是很清楚,中间到底涉及多少数据表,行,字段的修改,有没有队列机制,如何清除缓存,文件等等。不怎么敢直接走脚本修改删除数据库,也不愿意冒修改主库的风险,取舍排查之后,决定走http请求,从数据库里面通过select 得到要清理的帖子id,然后根据id走http请求删除,风险小,容易控制,恢复,排查异常,当然,http的问题是慢,所以后来我开了20个php进程删。从数据库里面select得到 id,两个板块,大概有130w数据要删,还有4w多的异常数据,也要清理,这个是删除的过程中发现的。

删本身难度不大,但是却有风险,我写了脚本,跑着,跑着,然后在屏幕上监测各种输出,还有不断的刷页面,看结果,是不是符合预期,有没有删错,速度如何,很快发现了清理不了的异常数据,到现在也不是很清楚这些数据的来源,我没有论坛的操作日志,为了删除这些,我还是仔细的读了一遍删除过程的代码,以及论坛获取正常帖子的代码,研究了数据的特征,分析了数据量,4w条,我开始以为是因为删除过程中没有加事务,在代码执行中的异常以及不回滚导致的数据的不完整。把问题推给异常总是这么的顺理成章。但是通过分析删除的输出日志以及结果数据的现状,还有未修改数据对比综合来推测,实际上,应该不是异常导致的,而是本来就是这样,为什么会这样,不知道,但是和我修改没关系,为了删除他们,我又写了一个脚本,连接主库,修改记录,把这些异常的修正成正常的,记录下id,然后走http接口,删了他们。

连接主库,然后修改数据是让人提心吊胆的事情。http错了再多,也就是几十上百条数据的事情,但是连接主库,一个不小心就可能清库,修改完之后,我开了20个php进程,看了下数据库平台显示的主从同步的压力,黄色,处于有压力,但是还能接受的地步。看着屏幕上疯狂的输出,惬意的喝杯水,有点得意,享受着跑数据过程中的宁静,然后,噩梦就在几分钟之后开始了。

正在清理的板块,没有数据了,空了,空了,空了,在我刚刚修改主库之后,在我疯狂删除的时候,一阵电流经过身体,各种清库的传说略过心头。欲哭无泪,赶紧连接数据库,select之后,发现数据还在,从库不可信,连主库,发现主库也没挂,数据也还在,心中稍定,总算不用再半夜里打电话给DBA求恢复数据。我肯定没有修改线上的代码,虽然修改了几次测试机的代码,代码没动,数据还爱,推测是缓存问题,也可能是有编辑修改了论坛数据,都有可能,排查,再次排查,一天内第几次追查数据了,着重看缓存问题,追查到是因为subforums + forum['threads'] = 0 导致的。subforums来自缓存,全局变量$_DCACHE,而$_DCACHE中没有有subforums 的信息,推测是因为什么导致subforums缺失,不断追查$_DCACHE来源,发现的确是来自文件缓存,数据源是forum_cache,一阵雀跃,以为找到了问题,然而并不是,并没有编辑在凌晨的时候去修改论坛的结构,forum_cache表里面数据正确 ,subforums 的确没有,这是一个错误,但是不是导致这个问题的错误,回头看forum 变量,一番追查,发现是因为自己不断的删除数据,forum['threads'] 不断减一,而forum['threads'] 并没有真正反映数据库帖子量的大小,数据一致性的问题,修改forum['threads']成正确的值,然后就可以了。

再次开动脚本,开始删数据,然后不断检查状况,一切正常,正常,正常,然后就删完了,

Leave a comment

Your email address will not be published.

*