服务器 CPU 被打满后我才懂:fail2ban 为何救不了你,防线前置才是关键

前言:装了 fail2ban 服务器还是被打爆?问题不在灵敏度,而在防线位置。fail2ban 是事后封禁,瞬时洪峰早已灌进 php-fpm。本文复盘一次真实攻击排查:HTTP/2.0 规则漏匹配、分布式 CC 攻击抓不到、参数与流量形态不贴,最终把 Nginx limit_req 限流挪到转发机边缘削峰,让防线前置,CPU 曲线才落回地平线。

服务器被打爆那晚,我重新理解了「防线前置」这四个字

前两天半夜,一个朋友给我发微信,就一句话,兄弟,我服务器 CPU 满了,fail2ban 也装了,为啥还被打?

后面跟了一张截图,监控曲线上一条红线,死死顶在天花板上,纹丝不动。

我当时第一反应也是懵的。。。装了 fail2ban 还被打成这样,那这玩意儿装来干嘛的。

一条红线,死死顶在天花板上
一条红线,死死顶在天花板上

先交代一下他的架构,不然后面没法聊。他是两台机器,前面一台 192.168.245.1 做转发,上面跑 Nginx 反代,把所有流量转给后面一台 207 的机器,207 上跑着 PHP 站点,php-fpm 在吭哧吭哧干活。fail2ban 装在转发机上。

攻击的形态也很典型,超多不同 IP,瞬时高并发,全打动态 URL,/user-sign、/oauth、/tag,一水儿的耗 PHP 的路径。

我登上去看,fail2ban 明明在工作,jail 是活的,已经封了 42 个 IP。

但 CPU 还是满的。

为什么?

排查下来,两个问题,一个是明面上的,一个是根子上的。

明面上那个,是 filter 规则只匹配了 HTTP/1.*,而人家攻击流量全走 HTTP/2.0。日志里哗哗地刷,fail2ban 一条都没数进去。等于哨兵只盯东门,贼全从西门进的城。

这个好修,把 failregex 改成 HTTP/1.0、1.1、2.0 全兼容就行。

但根子上那个,才是这次真正教我做人的。

就算规则全对,fail2ban 也救不了他。

你想想看 fail2ban 的工作方式,看日志,数次数,够数了,封 IP。它是事后封禁。日志都写完了,说明请求已经被后端处理完了。而攻击是瞬时洪峰,第一波请求在 fail2ban 反应过来之前,已经全部灌进 207 的 php-fpm 里了。等它封完,CPU 早就满了。

一句话,防线站错位置了。

那天修完之后,我一直在回味这个事,觉得里面有几条经验,不光是运维能用,你做任何「防御类」的事情,估计都用得上。我自己也踩过坑,想法可能不成熟,写出来跟大家聊聊,反正我觉得比直接甩一份配置文件有用。

1、先问防线站在哪,再问防线灵不灵

大多数人排查这类问题的第一反应,跟我朋友一样,是不是 fail2ban 没配对,是不是阈值太松,是不是该把 maxretry 调到 1。

都在调「灵敏度」,没人问「位置」。

fail2ban 这类工具,天生就是慢半拍的。它看的是监控回放,不是现场。看到小偷了,人早跑了,货也搬空了。

所以这次的核心改动,不是调 fail2ban,是把拦截整个挪到转发机的 Nginx 上。limit_req 限速,limit_conn 限单 IP 并发连接数,让洪峰在边缘就被削掉,请求根本到不了 php-fpm。fail2ban 降级,从主防线变成补刀的。

位置对了,灵敏度才有意义。

2、没验证过命中的规则,等于没有

HTTP/2.0 漏匹配这事,最气人的地方在于,它不是配置写错了,是配置「对了一半」。

规则能跑,jail 状态是 active 的,还在持续封 IP,控制台里 Banned IP list 排得整整齐齐,看起来一切正常,岁月静好。

但攻击换个协议版本,整条防线就静默失效了,而且失效得无声无息,没有任何报错。

防御类配置最大的坑就在这,它平时不响。你不去打它一下,你永远不知道它接不接得住。这块需要注意一下,任何安全策略上线,都拿真实日志或模拟请求验一遍命中,去看 fail2ban-client status 里的计数有没有涨。计数不动,一切白搭。

3、参数不是越狠越好,是越贴场景越好

原来的参数是 maxretry=2,findtime=300,听着很凶,两分钟内摸两次就封。

但对这种每个 IP 只打一两下、IP 数量巨大的分布式流量,它基本抓不到东西。反而正常用户要是共享出口 IP,比如公司一个出口、校园网一个出口,很容易被误伤。

改完是 maxretry=6,findtime=120,bantime 从 10 小时拉到 24 小时。

注意这里的逻辑变化,不是简单的松紧调整。窗口从 5 分钟收窄到 2 分钟,是在抓「短时间内的突发」,更贴这波攻击的特征。封禁拉长到一天,是让同一批 IP 别反复回来骚扰。参数没有标准答案,只有跟你的流量形态贴不贴这一条判断标准。

4、高危路径要单独照顾

全站一套限速策略,其实是偷懒。

日志里 /oauth/ 和 /user-sign/ 占了大头,最耗 PHP,那就单独给这俩上更严的策略,/oauth/ 的 burst 收到 3,/user-sign/ 收到 5,单 IP 并发都限到 10 个连接。普通页面维持全站的基础限速就好。

好钢用在刀刃上,好策略用在刀刃路径上。

洪峰在边缘被削掉,别让它灌进后端
洪峰在边缘被削掉,别让它灌进后端

顺着上面的再聊聊,我也得坦白讲,这套东西不是改完就一劳永逸的。

限流阈值调太紧,正常用户会撞一鼻子灰的 429。调太松,等于没防。那天改完,我也是让他盯着看了十来分钟,看转发机日志里 429 有没有出来,看 Total banned 有没有持续涨,看 207 的 php-fpm 有没有降下来,来回校准的。一开始笨拙很正常,甚至可能比手动看日志还费时间。

但它换来的是,你不用凌晨三点爬起来看 CPU 曲线。

聊到这,我突然想起人体的免疫系统。

皮肤和黏膜是第一道防线,物理拦截,不管来的是细菌还是病毒还是灰尘,先挡一下再说,即时生效,零延迟。适应性免疫是第二道,要识别病原体,要生成抗体,有记忆,很聪明,但是慢。你第一次遇上某个病毒,等抗体造出来,人已经发烧好几天了。

fail2ban 就是适应性免疫,Nginx 限流就是皮肤。

先接住洪峰的,从来都是最笨的那一层
先接住洪峰的,从来都是最笨的那一层

大多数人配安全策略的思路,是想装一个「聪明的」防线,指望它精准识别坏人再动手。

但真正先接住洪峰的,从来都是那个笨的、物理的、不挑人的第一层。

聪明,是用来收尾的。笨,是用来保命的。

那天晚上十一点多,朋友给我发来一张新截图。207 的 CPU 曲线,那条顶了一天一夜的红线,慢慢落回了地平线附近,一起一伏,像正常呼吸。

他发了三个字,活过来了。

我回他,以后别光问防线灵不灵,先问它站在哪。

比比说,磨平一些信息差。

/ 注意,本项目仅在 SyncMein 的500人小群分享。
/ 谢谢你看完了我的文章,我们下次再见吧。
/ 作者:明察
/ 投稿或爆料,请联系邮箱:mingcha@gqmg.com

关键词:fail2ban 防线前置, Nginx 限流削峰, HTTP/2.0 攻击漏匹配, php-fpm CPU 打满, 分布式 CC 攻击防护, limit_req 限速配置

© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容