|
去年冬天,慢速我帮一个做跨境电商的攻击朋友看服务器。他的漏洞站点跑在 Nginx 上,配置看着挺正常,修复可每到晚上八点左右,慢速CPU 就飙到 100%,攻击连接数暴涨到两万多。漏洞他以为是修复 DDoS,买了高防,慢速结果一点用没有。攻击我上去抓了个包,漏洞发现攻击流量小得可怜——每秒也就几十个请求。修复问题出在连接上:几千个连接挂在那里,慢速每个都只发了一半的攻击 HTTP 头,然后就不动了。漏洞 这就是 HTTP 慢速攻击。它不靠流量压垮你,靠的是“占着茅坑不拉屎”。 慢速攻击到底慢在哪 正常请求是这样的:客户端建立 TCP 连接,发完请求头,服务器回响应,连接关闭。整个过程几毫秒到几百毫秒。慢速攻击把这个过程拉长到几十秒甚至几分钟。常见的有几种玩法: Slowloris 最经典。攻击者开一堆连接,每个连接每隔几秒发一个字节的 HTTP 头,比如 GET / HTTP/1.1\r\n 之后,慢慢补 Host:、User-Agent:。服务器一看,请求还没结束,继续等。一个连接占一个 worker 进程或线程,几千个连接就能把进程池耗光。Apache 的 prefork 模式尤其怕这个,每个连接一个进程,内存直接吃满。 Slow POST 换个路子。声明一个巨大的 Content-Length,比如 100MB,然后每次只发几字节的 body。服务器老老实实等着收完,连接一直挂着。Nginx 默认的 client_body_timeout 是 60 秒,但攻击者只要在超时前发一个字节,计时器就重置,连接可以无限续命。 慢读攻击 反过来玩。客户端发完请求,服务器开始回响应,但客户端把 TCP 接收窗口设成零,或者每次只读一点点。服务器发送缓冲区满了,连接卡在那里,worker 被占用。这种对静态文件服务器特别有效,因为大文件传输本来就需要时间。 为什么你的防护没生效 很多人第一反应是加 limit_req 或 limit_conn。我朋友也加了,limit_conn 设成 50,结果攻击者用两千个 IP 各开 50 个连接,照样打满。限速模块管的是请求速率,慢速攻击的请求速率极低,根本触发不了阈值。 WAF 也未必拦得住。慢速攻击的请求头看起来完全合法,只是发得慢。基于规则匹配的 WAF 查的是内容,不是时序。除非 WAF 有专门的慢速攻击检测引擎,否则流量直接放行。 问题根源在于:服务器默认会为每个连接分配资源,并且愿意等。等多久?看配置。等的时候,资源就被占着。 修复方案:让服务器学会“没耐心” 核心思路就一个:给连接的每个阶段设死线,超时立刻断,不续命。 Nginx 上要改几个参数。client_header_timeout 默认 60 秒,改成 10 秒。这个控制接收请求头的总时长,从连接建立开始算,不是每次收到数据就重置。慢速发头的直接断。client_body_timeout 同样改成 10 秒,控制两次读 body 之间的间隔,不是整个 body 的接收时间。攻击者想靠单字节续命,没门。send_timeout 也要调,默认 60 秒,改成 10 秒,控制两次写响应之间的间隔,慢读攻击的克星。 还有 keepalive_timeout,默认 75 秒,改成 15 秒。空闲连接别留太久。keepalive_requests 设成 100,一个连接最多处理 100 个请求就关,防止单连接长期占用。 光调超时不够,还得限制单 IP 并发。Nginx 的 limit_conn_zone 配合 limit_conn,但要注意:limit_conn 只对处于读取请求头阶段的连接计数,正好覆盖 Slowloris。设成 10 到 20 比较合理,正常用户不会开这么多并发。 Apache 用户更麻烦。prefork 模式下,每个连接一个进程,MaxRequestWorkers 就是上限。要装 mod_reqtimeout,配置 RequestReadTimeout header=10-20,MinRate=500 body=10-20,MinRate=500。意思是:接收请求头最多 10 到 20 秒,且速率不低于 500 字节/秒。低于这个速率,直接 408 超时断开。这个 MinRate 很关键,它让“慢”本身成为被拒绝的理由。 一个容易忽略的点 调完这些参数,记得测。用 slowhttptest 或 hping3 模拟一下,看服务器能不能在 10 秒内主动断开。我见过有人把 client_header_timeout 改成 5 秒,结果移动网络下的正常用户也被断,因为 2G 网络发完请求头可能超过 5 秒。10 到 15 秒是折中值,兼顾安全和可用性。 另外,如果用了 CDN 或负载均衡,超时设置要在每一层都对齐。CDN 回源超时 60 秒,你源站 10 秒就断,CDN 那边会报 502。把 CDN 的回源超时也改成 10 秒,或者让 CDN 自己处理慢速连接。 慢速攻击不是新东西,2007 年就有了。但它一直有效,因为很多服务器还在用默认配置。默认配置假设客户端是善意的,而攻击者恰恰利用这一点。把超时收紧,让服务器在连接不活跃时果断放弃,问题就解决大半。剩下的,交给连接数限制和监控告警。 |