client_body_timeout 的核心作用是限制客户端两次发送 body 数据包的间隔时长而非总上传时间;仅当请求头完整接收且空行后开始计时,超时即断连释放 worker。

要防住慢速 POST(Slow Body)攻击,client_body_timeout 的核心作用不是限制“上传花了多久”,而是卡住“两次发包之间空等了多久”。设成 60 秒默认值,等于给攻击者发了一张长期占坑许可证——他只需每 30 秒发 1 字节,就能持续拖住你的 worker 进程。
它到底在防什么、怎么触发
这个参数只在满足以下全部条件时才开始计时:
- 请求头已完整接收(含
Content-Length或Transfer-Encoding: chunked) - 空行(
\r\n\r\n)之后,客户端开始发送 body 数据 - Nginx 在两次 TCP 数据包到达之间等待超时——注意:是“停顿间隔”,不是总耗时
攻击者正是利用这点:发完 POST /api 和头部后就卡住不发 body;或声明 Content-Length: 10MB,却每 20 秒只送一个字节。若你设为 60s,Nginx 就会傻等满 60 秒才断连,期间该 worker 无法处理任何新请求。
按业务类型设合理值,避免一刀切
统一设 5s 或 60s 都容易出问题。应匹配真实传输节奏:
-
纯 JSON API 接口(无文件、无大字段):设
10–15s。正常客户端完成 TLS 握手、序列化、网络发出,通常 2–5 秒内就传完 body -
管理后台文件上传(如 CMS 表单):可设
300s(5 分钟),但必须同步配client_max_body_size 100m,防止攻击者用超大声明+极慢发送耗尽缓冲 -
移动端接口(含图片/语音/弱网场景):设
60–120s。网络切换、休眠唤醒易造成短暂中断,过短会导致大量合法 408 -
流式或分片上传:设
60s即可,但要求客户端按约定频率(如每 30 秒)发送心跳或分片头,否则仍会被断
单靠它不行,必须组合防御
慢速 POST 是链式攻击,仅调 client_body_timeout 会被轻易绕过:
- 同步配
client_header_timeout 10s:防攻击者卡在 header 阶段不发 body,形成首尾夹击 - 开
reset_timedout_connection on:超时后直接发 RST,立刻释放 socket 句柄,避免 TIME_WAIT 堆积 - 设
client_max_body_size合理上限(如 API 设 20M,后台设 200M):超限直接返回 413,不进 timeout 流程 - 调
client_body_buffer_size匹配常见体大小(小接口用 128k,大上传用 2m~4m):避免频繁落盘,也不让慢连接长期持占内存 - 加
limit_conn perip 10:限制单 IP 并发连接数,防几百个慢连接打满worker_connections
验证是否真正生效
别只看配置 reload 成功,要实测行为:
- 用
curl -X POST http://host/api --data-binary @/dev/zero --limit-rate 100 -m 60模拟慢速发送(每秒 100 字节) - 观察是否在设定值附近(如设 15s,则约 15–18s)返回
408 Request Timeout - 查
error.log是否出现client timed out (110: Connection timed out) while reading client request body - 用
ss -i或tcpdump确认连接是被 RST 中断,而非自然 FIN 关闭











