网站被 CC 攻击的一次经历

一直感觉网站被攻击那都是新闻里的事情,可就是上个月,连续五六天收到服务器负载过高的警告邮件,看了一下进程记录发现是 PHP 占据了80%~90%的内存并且 System Load 都是100%,平均负载竟然是 “21.28 13.57 5.48″,这可不是开玩笑的。我又看了 Nginx 的访问日志,发现连续几天几乎在同一时刻有大量的 IP 疯狂请求网站,虽然比不上那些新闻中的攻击量,但也足够让我的小服务器挂掉。这时我意识到我网站被人盯上了,而且是 CC 攻击。于是乎,我便到处寻找防御的方法,这里呢,就记录一下整个过程,希望能帮助到那些跟我有同样遭遇的人。

开端

从十一月六号到十六号,每天的十一点到十二点之间,我收到了服务器高负载的警告邮件,一开始我没在意,可是连着几天后我觉得事情有点不对劲,就到服务器上看了一眼,发现是 PHP 几乎占据了全部的内存,于是我减少了 PHP 的最大进程数,这样做之后似乎有效,之后的几天都没收到警告邮件。在十一月底的时候我看了一眼 PHP 的日志,想找出 PHP 究竟出了什么问题,发现每次高负载的时候 PHP 都出现了这样的日志:

WARNING: [pool www] seems busy (you may need to increase pm.start_servers, or pm.min/max_spare_servers), spawning 16 children, there are 2 idle, and 28 total children

紧接着 PHP 的进程数就达到了上限,这时 PHP 日志又出现了这样的提示:

WARNING: [pool www] child 25422, script 'index.php' (request: "GET /index.php") executing too slow (30.032048 sec), logging

说明此时我的网站响应速度已经是巨慢的了,而且连着好几个这样的日志,于是我就查看 nginx 访问日志,这一看不要紧,发现在那一时刻有大量的 IP 大量访问网站地址,而且还是随机的地址,感觉它一下子请求了我博客中所有的地址,请求的速度大概是一秒十个以上。虽然它攻击的速度没那么大,直接访问静态的页面也不至于让服务器宕机,但是我网站可都是 PHP 动态页面,这大量的请求一下子都交给 PHP 去处理,PHP 肯定要炸了呀。

分析

这时我意识到我网站被人盯上了,可我只是搞了一个小博客玩玩而已,怎么会被人给盯上了呢?当然想这些也没用,还不如好好想想怎么防住这些攻击。在网上搜了一些相关的资料,才知道这种攻击属于 DDoS 的一种,但不是 DDoS,而是 CC 攻击,这两者最大的区别就是 DDoS 是针对 IP 的攻击,而 CC 攻击的是网页,也就是说,CC 攻击中每个请求都是合法的,就像是正常用户访问网页;CC 攻击的来源 IP 都是分散的,也就是通过代理服务器用大量 IP 来发送请求。攻击我的 IP 都是在一个24位的子网中,单靠防火墙是无法有效防止的,因为短时间内同一 IP 请求次数可能并没有达到屏蔽的量。由此可见,CC 攻击最可怕之处在于攻击的 IP 数巨大,单靠硬件防火墙根本无法屏蔽。

攻防之战

第一回合

CC 攻击有一个致命点,那就是它请求的都是动态资源,比如 PHP ,因此我就打算从限制 PHP 并发入手,减少 PHP 的并发数目,以防万一我还限制了 nginx 单个 server 的并发数目。对于我这种小博客,限制5个并发就足够了,也不会有那么多人同时访问我的博客。

隔了一两天我去查看 nginx 日志时又发现,攻击并未停止,而且攻击请求的返回状态码竟然是499,这个状态码我可第一次见,查了一下资料得知这个错误码的意思是 “CLIENT CLOSED REQUEST” ,也就是客户端关闭了链接,当然关闭的原因一般就是服务器处理请求处理的太慢,然后客户端就等不及了,直接关闭了请求。像极了我们平时打开一个网页发现等半天还是在转圈圈,于是就关闭了这个网页。既然出现了这个错误码,也就说明最终请求还是交给了 PHP 来处理,PHP 处理过慢,攻击者为了进行下一个攻击就关闭了这个请求,看来限制并发并不能挡住 CC 攻击。

第一回合我败 :(心碎)

第二回合

随后我又从防火墙屏蔽 IP 上入手,使用了张戈大佬写的 CCKiller 脚本,试图直接将 IP 用 iptables 来屏蔽掉。为了更好的统计 IP 访问次数,我还修改了脚本,让它只监听某一端口和某一状态的 IP 访问,同时将 IP 的屏蔽频率限制到了每2秒超过3次就屏蔽,虽然有点极端,可是为了挡住 CC 攻击也顾不了那么多了。第二天看了一下 nginx 日志,发现并不起作用 :(笑尿) 由于攻击者足足使用了一个段的 IP 来发送请求,同一个 IP 出现两次的间隔甚至超过了5秒,这也可以理解,毕竟一个段的 IP 都有254个可用 IP,一秒就算十次请求,要用完这254个 IP 也需要25秒,这让我怎么根据 IP 访问频率来屏蔽???算了,这回合我又输了 :(心碎)

第三回合

第三回合要从我无意间发现宝塔面板中的 NGINX 管理那里有一个过滤器,叫做 waf,其中的配置中有一个防 CC 攻击的配置说起。我试着启用了防 CC 攻击功能,并设置 CC 攻击触发频率为5次,触发周期为2秒。等到了第二天,发现 waf 的日志中并没有任何防住 CC 攻击的记录,看了一下 nginx 访问日志,还是有被攻击的大量请求。抱着好奇的心态,我看了一下宝塔使用的 waf 源码,发现是用 lua 写的,在源码中防 CC 攻击这一块,发现它是根据 IP + 请求的URL 作为依据来统计频率的,这玩意怎么能防住大量IP+随机URL请求呢?好吧,这一回合又是我输 :(心碎)

第四回合

经过上一回合的失败,我决定修改这个 lua waf ,在网上查了查,发现它是基于 Nginx 的 Lua 语言模块:”OpenResty” 开发的一个 nginx lua waf 防火墙,原作者是 @loveshell ,瞬间感觉这个项目好厉害,更加坚定了修改这个项目的决心。在看了几天源码之后,大概看懂了这个项目的思想,就开始动手改了。我首先改的是防 CC 的判断依据,将它由 IP+URL 改为了 IP+HOST,这样就可以防止随机 URL 请求。上线测试时发现对于某些特定 URL,比如小程序接口,会造成误杀的情况,因为小程序的一个页面会有好几个API 请求,于是又改进了原项目的 URL 白名单功能,修改为 HOST+URL 的白名单功能。修改完成,上线测试。结果嘛,还是失败了,毕竟还是使用 IP 来作为判断依据的。虽然能屏蔽住一些同一IP大量异常请求的攻击,但还是防不住之前的 CC 攻击。无奈,这一回合我又输了 :(心碎)

第五回合

到了这一回合,我决定从分析访问日志下手,肉眼看了N行日志之后,发现这些攻击竟然有一个相同点,那就是日志中都出现了”http://www.baidu.com/s?wd=6HJW”,看到这我想攻击可能是从百度索引来的,这才造成这么多的请求URL,也有可能是读取了我的站点地图,然后根据站点地图中的 URL 来作为请求 URL。既然这样那我总不能不让百度来索引我网站或者不用站点地图吧,这样子对搜索引擎太不友好了。这时,我转念一想,这些请求中为什么都要加一个类似”http://www.baidu.com/s?wd=6HJW”这样的来源 URL 呢?查了一下 nginx 的日志,发现这部分是请求头中的 “http_refer” 部分,也就是记录当前请求是从哪个 URL 来的。可能攻击者是让服务器认为这些请求是来自百度搜索,避免被屏蔽吧。

这时我转念一想,我为啥不根据 “http_refer” 来作为统计频率的依据呢?既然所有的攻击请求中都带有同样的 “http_refer”,我完全可以根据它来限制请求呀,这样子不管来源 IP 是啥,我都可以做到匹配了。既然有这个想法,就立刻动手改程序。就在前天,我又一次更新了 nginx lua waf 项目,添加了根据 http_refer 来限制访问的功能,并把它发布到网站中,静静地等待下一波攻击。

等待了一天,周六,没攻击我,今天,我看了一下 waf 日志,发现 http refer CC Deny 有了一条记录!激动的我赶紧查看 nginx 的访问日志,果然在十二点左右来了一波攻击,相同的手段:24位掩码的 IP 段、随机的请求 URL、相同的 http_refer,它终于来了!看了一下它所有的请求,在触发了 http refer cc deny rate 之后,所有请求都变成了 503 返回码,不再是 200 或者 499 了。我查看 PHP 的日志记录,并没有任何异常,服务器负载也没有任何异常!哈哈哈哈,这一回合算我胜了吧 :(太开心)

下面附上 waf 和 nginx 的访问日志:

[2018-12-09 12:13:50] "HttpReferCCDeny blog.sunriseydy.top - -" " ban a http_refer "  "Mozilla/5.0 (iPhone; U; CPU iPhone OS 5_1_1 like Mac OS X; en) AppleWebKit/534.46.0 (KHTML, like Gecko) CriOS/19.0.1084.60 Mobile/9B206 Safari/7534.48.3" "rule: http://www.baidu.com/s?wd=6HJW"

nginx访问日志

总结

经历了这次被攻击事件,我也学到了很多,也发现运维这个坑真的是深不可测 :(笑尿) 当然了,这次攻防之战也不一定就此结束,也不知道那小子会不会再来呢?不过嘛,魔高一尺道高一丈,想再来那我就再陪你玩一玩,我还能借此机会不断地提高自己呢 :(太开心)

对了,上面说的更新后的 nginx lua waf 项目已经被我放到了 ehaut 项目组下,链接在此:ehaut/ngx_lua_waf,我自己 fork 了一份用来开发,测试好后就会 push 到 ehaut 下的。之后呢,我会具体写篇文章说明这个项目的,感兴趣的朋友可以关注一下本站。


版权说明:
作品 sunriseydy 采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
文章内容如未说明均为原创,欢迎转载,但请注明原作者(sunriseydy)和原文链接(https://blog.sunriseydy.top/daily/web-attack/)
部分来自互联网的文章,如有侵权,请联系我,24小时内删除,谢谢

手机打开扫一扫即可访问本页面

感谢您的支持,SunriseYDY 会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

日出一点一 | 在探索的路上永不止步

分享到微博 分享到QQ 微信赞赏 在手机上阅读 点赞 2

“网站被 CC 攻击的一次经历”的8个回复

  1. 好像我网站去年就是这样,不过我没管他就是有时候打不开网站,然后清理服务器内存,然后在使用网站。过段时间网站内存有满了,后来就用了一个shell命令定时清理。半年后感觉服务器回复正常了。不知道我这个算不算是被攻击了呀。

    • @菜鸟头头 可以看一下网站访问日志分析一下。其实只要服务器内存大完全可以不管它

  2. “对于我这种小博客,限制5个并发就足够了,也不会有那么多人同时访问我的博客。”读出了满满的心酸 :(滑稽) :(滑稽)

  3. 攻击者:哈哈,我说攻击怎么失效了呢,原来如此,等我回去改下脚本卷土重来吧~

怼他/她 算了,不怼了

电子邮件地址不会被公开。 必填项已用*标注