$request_length是识别静态阻塞类攻击最灵敏的指标——它在请求接收完毕后立即生效,不依赖后端响应,也不受压缩编码干扰,能真实反映客户端发来的原始字节数。

直接看 $request_length 是识别静态阻塞类攻击最灵敏的指标——它在请求接收完毕后立即生效,不依赖后端响应,也不受压缩编码干扰,能真实反映客户端发来的原始字节数。当大量超长请求堆积在 Nginx 缓冲区却迟迟不被后端处理,就会引发连接挂起、worker 占满、新请求排队等典型“静态阻塞”现象。
为什么 request_length 能暴露静态阻塞
静态阻塞不是瞬时打垮服务,而是让少量恶意请求长期占用连接资源。这类攻击常见于:
- 伪造
Content-Length极大但实际只缓慢发送少量数据(Slow Body) - 构造 MB 级 POST body 并卡在传输中途,使 Nginx 一直等待收完才转发
- 高频提交超长 URL 或巨量 Cookie,导致单个请求总长突破几十 KB 甚至 MB
而 $request_length 正好在 Nginx 完整接收该请求(含头+体)后才赋值,此时若发现长度异常高、且 $request_time 显著大于 $upstream_response_time(后者为空或极小),就说明请求已收全但未发出——这就是静态阻塞的关键信号。
配置日志格式并提取关键字段
默认日志不记录 $request_length,必须显式定义:
log_format block_probe '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'$request_length $request_time $upstream_response_time '
'"$http_user_agent" "$http_x_forwarded_for"';
启用后,每条日志末尾会带三个数值:1248576 12.432 0.000 —— 分别代表请求总长(字节)、总耗时(秒)、后端响应耗时(秒)。重点关注 $request_length > 500KB 且 $upstream_response_time 接近 0 的记录。
用日志快速定位阻塞源头
不用人工翻查,用命令实时筛查:
- 查出所有已收全但未转发的长请求:
awk '$12 > 524288 && $14 == 0 {print}' /var/log/nginx/access.log - 按 IP 统计这类请求频次:
awk '$12 > 524288 && $14 == 0 {ip[$1]++} END {for (i in ip) print i, ip[i]}' /var/log/nginx/access.log | sort -k2 -nr | head -10 - 结合时间窗口看是否集中爆发:
grep '05/11/2026:22:' /var/log/nginx/access.log | awk '$12 > 524288 && $14 == 0'
配合超时参数做主动防御
仅靠日志是事后分析,需叠加 Nginx 原生超时控制防阻塞固化:
-
client_header_timeout 15;:限制请求头接收超时,防慢速 Header 攻击 -
client_body_timeout 30;:限制请求体接收超时,防 Slow Body 卡死 -
send_timeout 10;:限制响应发送超时,防后端僵死拖住连接 - 对已确认高危路径(如
/login、/api/search),可加if ($request_length > 1048576) { return 400; }快速拦截
注意:if 在 location 外慎用,建议放在具体 path 下,并确保与 limit_req 配合使用,避免规则冲突。










