client_body_timeout是两次TCP数据包间的最大空闲时间,非总上传时限;合理设置需匹配业务:API设15–25s、文件上传设300s(配body大小限制)、移动端设60s;须组合client_body_buffer_size、limit_conn、proxy_read_timeout等协同防御。

client_body_timeout 不是用来限制大文件上传总时长的,设成 300s 并不能让 2GB 文件稳稳传完——它只管“两次发包之间空等多久”,超时就直接断连、返回 408。
client_body_timeout 是什么,不是什么
它监听的是 TCP 数据流中两个有效数据包之间的最大空闲间隔。一旦客户端开始发 body(比如 POST 的第一字节),Nginx 就启动这个计时器;下一段数据没在 client_body_timeout 内到达,连接立即关闭。
它不控制:
- 整个请求头+body 的总耗时(那是
client_header_timeout+client_body_timeout分段叠加) - 后端处理时间(那是
proxy_read_timeout的事) - 文件落盘或缓冲区大小(那是
client_body_buffer_size和client_max_body_size管的)
典型误用:把 client_body_timeout 设为 600s 想“支持大上传”,结果攻击者每 59 秒发 1 字节,照样拖满 worker 连接池。
不同业务场景下怎么设才不误杀也不放行
关键看真实客户端的数据节奏,而不是文件体积本身:
- 纯 JSON API(无附件):
client_body_timeout 15s。正常浏览器/APP 在 TLS 握手、DNS 解析后,10 秒内必发完 body - CMS 后台表单(含图片 Base64 或小文件):
client_body_timeout 60s,配合client_max_body_size 20M - 管理后台文件上传(支持百 MB):
client_body_timeout 300s,但必须加client_max_body_size 100M,否则攻击者声明Content-Length: 10G就能卡住内存缓冲区 - 移动端接口(含语音/图片):
client_body_timeout 60s,网络抖动常见,低于 30s 容易触发批量 408
绝对不要设为 0 或 1s —— 丢包重传、NAT 超时、中间代理缓存都会导致合法请求被截断。
单设 client_body_timeout 为什么防不住慢速攻击
它只是防御链上的一环,缺了其他配置,等于只关了一扇窗却留着三扇门:
- 没调
client_header_timeout?攻击者可以只发POST /就停住,卡在 header 阶段,client_body_timeout根本不触发 - 没配
limit_conn?一个 IP 开 500 个慢连接,worker_connections 直接打满,新请求全进不了队列 - 没开
reset_timedout_connection on?超时后只发 FIN,系统要等四次挥手完成才释放 socket,TIME_WAIT 堆积更快 -
client_body_buffer_size设得过大(如 16M)?每个慢连接都占满一块内存,几百个就 OOM
推荐最小闭环组合:client_header_timeout 15s + client_body_timeout 15s + reset_timedout_connection on + limit_conn perip 10 + client_max_body_size 20M。
怎么验证它真正在起作用
别只看配置 reload 成功,用 curl 模拟慢速行为最直接:
curl -X POST http://localhost/api \
-H "Content-Type: application/json" \
--data-binary '{"key":"value"}' \
--limit-rate 50 \
-m 120
其中 --limit-rate 50 强制以 50B/s 发送,若你设了 client_body_timeout 10s,大概第 10–15 秒就会收到 408;同时检查 Nginx error log 是否出现 client timed out (110: Connection timed out) while reading client request body。
真正容易被忽略的是:这个超时判断发生在内核 TCP 层收包之后、Nginx 用户态读取之前。如果系统 net.ipv4.tcp_fin_timeout 太短,或中间有 LVS/F5 等设备做了连接复用,实际表现可能和预期偏差较大——得结合 tcpdump 抓包确认 FIN/RST 是否由 Nginx 主动发出。











