client_header_timeout是防御Slowloris攻击的第一道防线,从首字节起计时至完整请求头接收完毕,超时即返回408;client_body_timeout和send_timeout分别控制请求体接收与响应发送的空闲间隔;keepalive_timeout配合reset_timedout_connection可快速清理僵尸连接;还需结合缓冲区调优、连接限流与慢速请求验证实现综合防护。

client_header_timeout:第一道防线,专治“只连不发”
Slowloris 攻击者建好 TCP 连接后,并不发送完整请求头,而是每十几秒发一个 User-Agent: 或自定义字段,让 Nginx 一直卡在“等头部收全”的状态。默认 60 秒超时,意味着一个 worker 可能被上百个半开连接拖死。client_header_timeout 就是关紧这扇门——从收到第一个字节起计时,到完整请求头(含 \r\n\r\n)接收完毕为止;超时即返回 408 并断连,不进 upstream、不占后端资源。
合理取值需结合业务实测:
- 普通 Web 页面或 REST API:设为 5–10 秒。绝大多数客户端毫秒级发完头,10 秒足以覆盖弱网移动设备
- 内网服务或可信网关后:可压至 3 秒,链路稳定无中间延迟
- 含大量 Cookie 或 SSO 头的场景:先用
log_format记录$request_time,观察真实 P99 头部接收耗时,再加缓冲(通常 ≤15 秒)
client_body_timeout + send_timeout:堵住慢传体与慢读响应
client_body_timeout 控制接收请求体时两次数据到达的最大间隔。它不看总上传时间,只盯“空闲多久没来新数据”。攻击者声明 Content-Length: 10MB 却每分钟只发 1 字节,就靠这个参数识别并切断。
send_timeout 则管 Nginx 往客户端发响应的过程。当用户窗口极小或网络极差,Nginx 缓冲已满却迟迟无法写出,就会卡住连接。设太长易被 Slow Read 利用;设太短又误伤真实弱网用户。
- 常规页面/接口:两者均建议 5–10 秒
- 文件上传系统:
client_body_timeout可放宽至 300 秒(5 分钟),但必须配合client_max_body_size限制大小 - 流式响应(如 SSE):需大幅调高
send_timeout,并关闭proxy_buffering
keepalive_timeout + reset_timedout_connection:清空“僵尸连接”
keepalive_timeout 不是防攻击主力,却是资源泄漏关键点。它定义长连接空闲多久后关闭。默认 75 秒太长,尤其在攻击下会堆积大量 TIME_WAIT 状态连接。
仅设 timeout 不够硬,必须搭配 reset_timedout_connection on。它让 Nginx 超时后直接发 RST 包中断连接,而非温和的 FIN,从而更快释放 socket、减少 TIME_WAIT 滞留,避免连接表被填满。
- 对外服务:建议 keepalive_timeout 5–10 秒,并始终开启
reset_timedout_connection on - 内网服务:可设为 30 秒,但仍推荐启用复位机制
- 禁用不必要的 KeepAlive:若业务基本无连续请求,直接设
keepalive_timeout 0
配套加固:缓冲区、连接限流与验证手段
单靠超时参数容易误杀合法请求,也挡不住多 IP 扫荡。必须组合以下配置:
-
调大 header 缓冲区:用
client_header_buffer_size 1k和large_client_header_buffers 4 8k避免因缓冲不足导致合法大头被截断重试,反而延长等待 -
限制单 IP 初始并发:配合
limit_conn_zone $binary_remote_addr zone=addr:10m与limit_conn addr 10,防止攻击者用多个源 IP 同时建连 -
验证是否生效:用
curl -v --limit-rate 10 http://your-site/模拟慢速头,观察是否在设定时间内返回 408;同时检查 error.log 是否出现client timed out while reading client request headers











