0x01 前言

在4月10日这天,我的博客遭遇了建站以来首次攻击,包含DDOS与CC攻击。虽然在调整防御策的时候经历过几次的短暂服务中断,但是整体来看还是挺成功的。

在遭受攻击前的过去2周里,我将站点的架构做了大调整,已经将数据库、PHP后端与前端进行分离。前端的nginx仅仅起到一个反向代理器的作用。

不知道攻击者的目的是什么,我的服务器仅运行着一个小博客,今天我针对这次事件做个详细的记录。

0x02 第一波攻击

  • 12:45:32 服务器监控告警,上行带宽超过限制:

  • 随即通过SSH登入服务器,发现大量处于TIME_WAIT状态的连接:

  • 通过iftop发现众多IP访问HTTP端口:

 

当时没有保留截图,这里仅展示当时所用的命令

  • 确认问题后随即通过iptables封禁80端口传入的请求:

  • 12:51:33 使用iptables封禁80端口后,流量随即下降,以下是告警消除通知:

  • 上行带宽恢复的同时,我检查了用于日志分析的ELK集群,发现攻击开始于12:44:59,每秒并发在5k~8k之间,并且还在持续:

  • 开始调整内核参数、启用防CC手段、调整fail2ban策略
  • 13:15:00 首波攻击结束,越30分钟的时间内,nginx共计收到约3,030,617次请求,记录到来自世界各地的1600多个IP地址:

此次攻击所跑的流量并不大,nginx的日志如下:

可以看到,肉鸡通过HTTP协议访问我博客的域名,但我博客是强制使用HTTPS的,所以nginx返还了301给肉鸡。想不到肉鸡居然跟随了301进行跳转,生成了以下日志:

所以每次攻击都会产生2次请求,这对我服务器的CPU与网络都造成极大的影响。

0x03 第二波攻击

我还以为攻击就这样结束了,然而并不是,在我正准备洗澡的时候,第二波攻击来了。

  • 20:20:33 服务器监控告警,上行带宽超限:

其实这一波攻击不应该成功的,因为我在回到家后多次对fail2ban的策略进行调整,导致上午ban掉的IP全被释放了,因此第二波攻击才有机可乘。

  • 20:28:00 受限于fail2ban的性能,在经过8分钟后,已经快把所有的恶意IP都拉到黑名单了:

可能是因为攻击者的肉鸡都已经打完,连接数在缓慢地下降,而我的站点已知处于正常运行的状态。这一波的攻击从8点20分左右一直持续到11号的0点前后才结束。

0x04 防御

0x04.1 网站架构

我博客的架构在3月底至4月初已经完成改造,详细的描述我会在后期撰写文章说明,这里先描述下大体情况。

用户访问到的服务器仅用于前端,仅运行着nginx用于反向代理。我站点的mariadb、apache与PHP已经迁走,甚至zabbix proxy server也已经完成迁移。因此,用户访问到的页面都是缓存在本地的静态页面,只会对带宽造成压力,而后端依然坚挺。

我的后端运行着mariadb、Apache与PHP,且为双节点热备模式:一台运行在我家里的服务器中,另一台则运行在某云服务商的VPS中。

其中,运行在我家中的节点为主节点,在心跳包正常的情况下,所有需要后端请求的流量都会发送至这里。为了安全起见,一切需要登入后台的操作仅能在我家中操作,通过公网访问敏感目录一律返还403。

另外还解决了双节点的文件、session与数字证书同步等问题。

最后,所有静态文件都使用CDN进行分发,减轻前端服务器的压力。

这个架构较以前的一箩筐模式在抗攻击能力上有质的飞越:

  • 当遭受攻击时,无需担心后端崩溃,可在后端建立WAF,对特定的客户IP进行拦截;
  • 当遭受攻击时,通过前端服务器可以更便捷地拦截流量;
  • 当遭受攻击时,可以随时调整DNS记录,通过分流肉鸡流量进行防御;
  • 静态页面能有效提升防御能力
  • … …

更多内容与实现方式计划在新文章中详细阐述。

0x04.2 HttpGuard

HttpGuard原本是一个开源项目,但是作者已经转为收费服务了。但是开源版本的源代码依旧可以在GitHub中下载并安装使用,简单的安装与配置可以参考以下文章:

原本我并没有启用HttpGuard,在遭受攻击后重新调整并启用防御功能。

首先启用被动防御,限制请求模块:

每分钟请求超过100次的访客将会被要求输入验证码:

因为我站点中的静态文件使用了CDN,所以在正常浏览情况下,同时打开多个页面也不会出发该规则。

因为肉鸡中的自动化程序不会输入验证码,在超过10次失败后将被拉黑24小时:

但是这个设定并不会调用iptables,而是返还HTTP响应码,默认情况下是返还444,但为了方便fail2ban统计,我将返还的响应码改为403:

但是我并未就此罢休,我还设置了自动启用的防御模块:

当在2次检查中,10秒内的连接数超过150,则启用重定向模块。一般情况下,CC攻击一般不会跟随跳转,所以这个重定向模块会有一定的用处,但对SEO则是一个灾难,所以该模块仅在必要时启用。

0x04.3 iptables & netstat & iftop

这三款软件在遭受攻击时非常有用,首先是iptables,在设置防御或者拦截规则时,首先采用丢包的模式而不是拒绝,因为丢包不需要给客户端返还内容,可以节省带宽,也可以起到一个迷惑攻击者的作用。

另外,在手动添加拦截规则时建议将规则插入到第一行,而不是最后一行,这样可以确保规则一定会生效。但是这种临时的规则并不需要保存,所以需要删除规则时,仅需要reload即可:

  • -I:将规则插入到INPUT链的首行
  • -p:匹配TCP协议
  • –dport:首访端口为HTTP的80端口
  • -j:将数据包丢弃

而netstat则可以检查当前的网络连接情况,例如:

当需要统计某个状态的连接数时,可以使用以下命令:

在遭受攻击时,服务器可能变得非常缓慢,所以命令越简单越好。

最后是iftop,一款实时展示网络连接情况的软件,使用iftop命令打开展示界面后,分别按下以下按键:

  • t:在同一行内展示上下行情况,节省空间
  • T:展示总流量
  • p:展示端口

最后的界面应该类似这样的:

但是这里面的端口太混乱了,我只需要HTTP与HTTPS的访问情况,这时候按下小写字母“L”,输入:

后回车即可查看HTTP与HTTPS协议的连接情况。

先使用软件分析实际情况,然后进行分析,最后进行策略调整。

0x04.4 fail2ban

fail2ban的基本安装配置可以参考以下文章:

在第一波攻击的时候我就调整了策略,收紧对nginx日志中响应码为403的访客的控制,一旦超过限值则调用iptables将其请求丢弃:

一般情况下不会触发403响应码,如果客户在30分钟以内触发超过10次403状态码,则拉黑24小时。

但通过检查ELK中的分析发现,肉鸡触发最多的并不是403,而是301与200。为此,针对我的实际情况,制定了以下规则

0x04.5 nginx

但是在第二波攻击时我又发现访问次数上限太高,fail2ban的压力太大。因此,我利用nginx自带的limit_req模块进行限流:

配置完nignx后可以发现可疑的IP确实被fail2ban中检测403的jail规则拦截了。

但我并没有删除fail2ban中检测301与200的规则,这部分还需要进一步测试,以便分析性能与可靠性。

0x04.6 内核

针对TIME_WAIT的问题,我选择通过调整内核的方式进行优化:

调整后发现异常的连接数大幅度减少。

0x05 数据

上下行峰值为44Mbps左右:

CPU负载情况如下图:

因为前端服务器有缓存与防护,所以后端服务器一切正常:

流量也正常:

数据库也未见异常:

从中午12点至第二天的0点这中间的12小时里,共计接受了10,178,740次访问、流量为1.058GB,共记录到3,004个IP地址:

流量与请求分布情况如下图:

肉鸡主要来自亚洲,大部分来自我国:

CDN也受到波及,跑了一波流量,但随后触发了抗CC规则,IP被拉黑了:

攻击CDN的肉鸡大多来自亚洲,以我国的IP为主:

0x06 结语

我博客的架构与防护软件的功劳不可小觑,另一部分因素是攻击者的肉鸡不够了,不过从大体看来,这次攻击的肉鸡质量不错。

我比对了两波攻击的IP,发现大部分都是一样的。肉鸡居然可以用那么久,由此可见,此次肉鸡的质量非常好。

只是不明白为什么要选择我这个小博客作为目标 🙁