线上业务毫无征兆地出现访问卡顿,监控后台却显示带宽和服务器负载并未达到瓶颈,这种情况往往指向一种隐蔽性极强的攻击方式——慢速攻击。攻击者通过建立大量连接并刻意以极低速率发送或读取数据,耗尽服务器的连接池资源,导致正常用户无法建立新的TCP连接。要根治这类问题,不能仅依赖WAF或网络层防火墙,必须在Apache服务器本身的编译源头和超时参数两个维度进行深度加固。
模块裁剪:从源码层面缩小攻击面Apache HTTP Server的默认安装包为了满足通用性,通常会预编译大量模块。但每一个被加载的模块都是潜在的攻击面,尤其是一些处理特定协议或复杂逻辑的模块,一旦存在未公开的漏洞,就可能被利用来制造拒绝服务。模块裁剪的核心思路是“最小化原则”,即只保留业务必需的模块,从二进制层面移除无关代码。
执行模块裁剪前,必须彻底梳理业务依赖。通过httpd -l可以查看静态编译的模块,通过httpd -M可以查看当前已加载的动态模块。很多运维人员习惯直接注释httpd.conf中的LoadModule指令,但这只是阻止模块加载,模块文件依然存在于磁盘上。更彻底的做法是在编译阶段就进行控制。如果采用源码编译部署,应该在./configure步骤中明确指定启用的模块列表。例如,一个纯静态资源转发或反向代理场景,完全可以禁用PHP、CGI、DAV等复杂模块:
./configure \ --prefix=/usr/local/apache2 \ --enable-modules="dir mime authz_core authz_host log_config" \ --enable-mods-static="unixd" \ --disable-cgi \ --disable-cgid \ --disable-include \ --disable-dav \ --disable-status \ --disable-userdir \ --disable-autoindex
对于已经通过二进制包安装的Apache,虽然无法重新编译,但可以彻底删除不需要的模块文件。模块文件通常位于modules目录下,扩展名为.so。在删除前务必做好备份,并逐一确认模块间依赖关系。例如mod_filter和mod_deflate存在依赖,删除前需用ldd命令检查动态链接库依赖。删除无关模块后,还需要在配置文件中注释或删除对应的LoadModule行,并执行httpd -t进行语法检测,最后优雅重启服务。这种物理删除比单纯注释加载指令更彻底,即便配置文件被意外修改加载了已删除模块,服务也无法启动,从而避免了错误配置引入的风险。
另一个常被忽视的点是MPM模块的裁剪。Apache提供了Prefork、Worker和Event三种多处理模块,但生产环境只需要其中一种。在编译时可以明确指定MPM类型,避免将多个MPM编译进同一个二进制文件。例如在高并发长连接场景下,Event MPM是首选,编译时加入--with-mpm=event即可。如果服务器上同时存在多个MPM模块文件,虽然运行时只会加载一个,但多余的模块文件仍然可能被恶意本地脚本利用进行权限提升,因此物理删除多余的MPM模块文件同样是加固的重要一步。
请求超时参数体系:切断慢速连接的逻辑链条慢速攻击的本质是长时间占用连接而不完成数据传输。Apache提供了多个时间维度的参数来控制连接生命周期,这些参数分布在核心配置和各个模块中,需要协同调整才能形成有效的防护网。最核心的参数是Timeout指令,它定义了Apache等待各种I/O操作完成的秒数,默认值通常为60或300秒。这个值在面临慢速攻击时显得过于宽松。攻击者可以在发送请求头时每30秒发送一个字节,就能让连接一直存活。将其调整为10到15秒是一个比较平衡的起点,但需要注意如果后端有耗时较长的CGI脚本或代理请求,单独调小Timeout可能导致正常请求被误杀,因此需要结合其他参数分层控制。
Timeout 15
mod_reqtimeout模块是防御慢速请求头的专用武器,它允许对请求头和请求体的接收阶段分别设置超时。这个模块在Apache 2.2.15及之后版本中默认启用,但很多默认配置并未充分发挥其作用。RequestReadTimeout指令可以精确控制客户端发送数据的最小速率和超时时间。一个有效的配置示例如下:
RequestReadTimeout header=5-10,MinRate=500 body=10,MinRate=500
这表示请求头阶段,客户端必须在5秒内开始发送数据,并且整个请求头的接收速率不得低于每秒500字节,同时给予10秒的最大完成时间。请求体阶段同样设置了最小速率和超时。MinRate参数是反慢速攻击的关键,它直接限制了客户端发送数据的下限速度,那些以每秒几个字节速率缓慢发送请求体的攻击行为会被立即触发超时断开。调整MinRate时需要结合业务实际请求体大小来计算,避免文件上传等正常业务被误伤。如果业务中存在大文件上传,可以为特定路径单独调整这个值,通过Location或Directory容器覆盖全局设置。
KeepAlive相关的参数也是慢速攻击利用的重灾区。KeepAliveTimeout定义了在持久连接中等待下一个请求的秒数,默认值通常为5秒,这个值本身不算高,但如果MaxKeepAliveRequests设置过大,攻击者可以在单个TCP连接上发起大量慢速请求,逐个消耗超时时间。将MaxKeepAliveRequests降低到100到200之间,可以限制单个连接上的请求数量上限,迫使攻击者频繁建立新连接,增加其攻击成本。同时,KeepAliveTimeout可以进一步缩减到2到5秒,减少空闲连接的等待时间。
KeepAlive On MaxKeepAliveRequests 100 KeepAliveTimeout 5
mod_qos和mod_evasive等第三方模块提供了更细粒度的速率限制,但在使用前需要评估其与现有参数体系的兼容性。mod_qos可以基于IP地址或URL路径限制每秒最大请求数、连接数和带宽,这能有效补充Apache原生参数在频率控制上的不足。不过引入第三方模块本身也增加了攻击面,需要在功能增益和安全风险之间权衡。如果业务场景允许,优先使用Apache原生参数和mod_reqtimeout的组合,这是最稳定且无需额外维护的方案。
连接状态管理与系统层协同Apache层面的参数调整需要与操作系统TCP/IP协议栈的超时设置协同工作,否则会出现应用层已经放弃连接,但内核仍然保持TCP连接的情况,导致资源无法真正释放。Linux系统中,tcp_fin_timeout、tcp_keepalive_time、tcp_keepalive_intvl和tcp_keepalive_probes等内核参数直接影响TCP连接的生命周期。tcp_fin_timeout默认值为60秒,表示FIN_WAIT_2状态的最长存活时间,可以降低到30秒。tcp_keepalive_time默认7200秒显然太长,调整为600秒左右可以更早地探测死连接。但要注意,TCP KeepAlive探测本身也会产生微小流量,在极端高并发场景下需要评估其开销。
Apache的mod_status模块在防御阶段应谨慎开启。虽然它提供了实时的连接状态和请求详情,有助于分析攻击特征,但ExtendedStatus On会记录每个请求的客户端IP、请求URL和处理时间,在遭受攻击时大量请求会迅速填满状态页面,不仅消耗内存,还可能泄露正常用户的访问路径。如果确实需要监控,建议通过条件限制只允许内网特定IP访问/server-status页面,并在非调试期间关闭ExtendedStatus。
日志层面的优化同样影响性能。慢速攻击会产生大量状态码为400或408的请求记录,如果使用默认的LogLevel warn或更高粒度,每个被超时断开的连接都会写入错误日志,瞬间的磁盘I/O飙升可能成为二次伤害。将LogLevel调整为crit或error,并考虑将访问日志的记录条件化,例如只记录非408状态码的请求,可以减少无效日志的写入压力。使用rotatelogs或管道日志时,也要确保日志处理程序本身不会因为突发流量而阻塞Apache工作进程。
分层防御与持续验证参数调整完成后,必须通过实际测试验证配置的有效性。使用slowhttptest这类工具可以模拟Slow Headers、Slow Body和Slow Read等多种攻击模式。测试时应从内网发起,逐步增加连接数和慢速速率,观察Apache的连接状态和系统资源变化。重点关注MaxClients或MaxRequestWorkers的消耗情况,如果攻击连接数达到上限后正常请求仍能获得服务,说明参数生效。如果攻击连接将工作进程全部占满,则需要进一步缩短超时或提高MinRate。
测试过程中要同时监控ss -s命令输出的TCP连接状态分布,大量SYN_RECV或CLOSE_WAIT状态可能说明参数调整后连接关闭流程存在问题。TIME_WAIT状态的连接过多则需要调整内核参数net.ipv4.tcp_tw_reuse和tcp_tw_recycle(在较新内核中tcp_tw_recycle已被移除,需注意内核版本兼容性)。
模块裁剪和参数调整不是一次性工作。每次Apache版本升级后,默认配置文件和模块列表可能发生变化,需要重新审查。建立配置文件的版本管理和变更审计机制,将安全基线纳入自动化部署流程,才能保证每台服务器都处于预期的加固状态。业务迭代过程中新增的功能可能引入新的模块依赖,在发布前应评估新增模块的必要性和安全性,避免为了一个小功能而加载一个功能庞大的模块。
最终,Apache层面的防护应与网络层的SYN Cookie、连接限制以及应用层的验证码、频率限制等手段结合,形成从网络到应用的纵深防御体系。没有单一参数能够完全杜绝慢速攻击,但通过模块裁剪缩小攻击面,再配合精确的超时参数控制连接生命周期,可以大幅提升攻击者的成本,保护正常用户的访问体验。
