今天遭遇来自自己的404攻击,网站从早上开始流量巨大,响应迟缓。我们上午到达工作岗位的时候,首页已经难以打开。于是立即远程登录服务器,检查Web服务器工作状态——CPU占用正常,内存占用低;又检查数据库服务器和图片服务器,发现工作状态良好。于是重启Web服务器,首页响应速度马上提高,于是很满意,以为问题解决。
中午吃完饭,突然接到来自数据中心机房的电话,说我们的服务器占用带宽超出流量限制,叫我们考虑是否购买额外的带宽。我们大吃一惊,因为几天以前我们检查还发现平均带宽使用率仅30%左右,峰值使用也没有超出限额。另一方面,服务器又慢如蜗牛。看来问题并没有解决,立即开始重新排查。
从数据中心发来的最近一天的带宽使用统计图上,我们的带宽曲线就像被生硬地抬高了一大截,超出了限制。第一反应就是,遭到攻击了。登录服务器查看Web访问日志文件,居然高达二点几GB,错误日志更是达到4GB而自动分割。难道真是遭到攻击了?决定马上分析日志文件,找出攻击的源头,并封禁攻击者的IP。
巨大的日志文件被压缩打包并准备下载——因为服务器端没有分析工具——但这个下载的过程是很缓慢的。另一方面,我们开始分析可能的攻击类型。第一个被排除的是ping攻击,因为那是一种很原始的攻击方法,并且攻击者自己也不好受(有多少数据发来,就有多少数据返回)。我们用tcpdump监测服务器的数据包,发现绝大多数数据包都是走tcp80端口的,只有极少数数据包走了22端口(ssh,我们远程登录用的端口)。
为了查出谁是罪魁祸首,我们决定监测30秒80端口的数据包,看看他们都来自哪里,流向何方。30秒我们抓到了70000+数据包——那几乎是我们服务器带宽的极限。抓到数据之后的分析让我们无所适从,因为似乎所有用户均匀递减地分享了这数万个数据包。而且收发的数据包数量也相当地平衡。但从另一个方面来看,有谁会在短短30秒内发起超过1500次HTTP请求呢?
问题的原因随着Apache访问日志的下载完毕浮出水面,分析一开始就发现一个怪异的现象,高达2GB的访问日志居然都只是同一种记录,请求服务器的404.php页面发生了404错误。404.php是一个自定义错误处理页面,几个星期前我们曾在Apache上增加一个重定向错误页面的选项,将404错误重定向到这个页面,但是这个页面里放什么东西,当时没有讨论清楚,所以这个页面也一直没有做。虽然这个选项在几个星期以前打开了,但是一直都没有发挥作用,因为Apache没有重新启动。直到昨天,为了新绑定一个网站域名重启了服务器,就造成了今天的灾难。
事情就是这样的:今天404重定向功能生效了,访问的页面找不到时就会打开404.php这个页面。用户打开网站访问,遇到一些死链接,会触发404错误,于是Apache告诉用户的浏览器,重定向到404.php。用户的浏览器会自动请求404.php这个页面,结果404.php不存在,又会触发一次404错误,Apache会再次告诉用户的浏览器,重定向到404.php这个页面。用户的浏览器会傻不拉唧地再次请求404.php,于是陷入一个反复循环——如果你调用的页面不存在,不论它是什么页面,那么去调用另一个不存在的页面。
从问题再次发现到问题解决,花了3个多小时,如果从问题发生算起,那就已经是快20小时了,其间我们差点报了警。大家都说,是我们自己把自己玩死了。反思一下,我们花了如此之多的时间才解决这个问题,解决问题的过程也的确可圈可点。比如那个2G的访问日志,哪怕只是打开看一下,翻个三五页,也能马上揪出问题的根源,但我们却花了快两个小时去下载它。我们太相信自己的那个假设:我们遭到攻击了,我们又太不相信自己能人工地简单分析一下2GB的日志文件。
再深层次地想一想,这应该是一个配置管理的问题:错误处理页面没有配合服务器设置的修改,而且我们以前遇到过同类问题,比如我们常常会面对代码修改了数据库却 没有改引发的SQL查询错误;或者还有数据库已经为新功能要求修改了数据表,但是处理新功能的代码没有跟随数据库变更一起发布而引发的的错误。只不过以前 的这些错误比较容易找出原因,今天的这个问题我们花了更多的心思罢了。
从风险防范的角度来说,虽然这一次不是来自别人的攻击。但是我们确实没有一个有效的手段去防御、发现和应对网络层攻击。我一直都只是一个做程序的,从来只从应用层安全的角度出发分析和考虑网络安全的问题。但随着公司越来越大,恐怕总会有包括但不限于竞争对手的小人使用黑客技术来关怀我们的网站。