最有效识别恶意超大请求的方法是记录并分析 $request_length 变量,它精确反映原始请求字节数,需自定义日志格式、设定阈值、结合限流与特征匹配实现事前防御与事后分析闭环。

直接看 $request_length 是最有效的办法——它代表客户端发来的完整原始请求字节数(含请求行、所有 Header 和整个 Body),不依赖后端解析,也不受压缩或编码干扰,天然适合在 Nginx 代理层第一时间识别恶意超大报文。
必须显式记录 $request_length 才能分析
默认日志格式(如 combined)不包含这个变量,必须自定义 log_format:
log_format secure_log '$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"';
access_log /var/log/nginx/access.log secure_log;关键点:
-
$request_length要写在固定位置(比如第12列),方便后续用awk或日志平台按列筛选 - 补充
$upstream_response_time,可区分是后端卡住(该值大),还是请求本身异常(该值接近 0 但$request_length极高) - 保留
$http_x_forwarded_for,避免多层代理下丢失真实源 IP
设定合理阈值并快速定位异常
不要靠人工翻日志。把 $request_length 当作数值字段处理:
- 查单次请求超过 5MB 的记录(单位:字节):
awk '$12 > 5242880 {print}' /var/log/nginx/access.log - 按 IP 统计 1 分钟内发送过 3 次以上
$request_length > 1MB的请求:awk -v start="25/May/2026:17:" '$0 ~ start && $12 > 1048576 {ip[$1]++} END {for (i in ip) if (ip[i] >= 3) print i, ip[i]}' /var/log/nginx/access.log典型攻击特征:
- 请求方法为
POST,但路径是/login、/search、/api/submit等非上传接口 -
$body_bytes_sent很小(如 < 100 字节),说明后端几乎没返回内容 -
$upstream_response_time接近 0,但$request_length达几 MB → 请求已收全却未转发,疑似静态阻塞
结合配置做闭环防御
光靠日志是事后分析,需叠加 Nginx 原生控制:
检查
client_max_body_size是否与业务匹配:若大量413出现在$request_length接近该值处,说明限制过严;若200或500对应超大$request_length,则可能是攻击绕过体长限制(例如靠巨量 Cookie 或长 URL)。-
对高频超长请求主动限流:
map $request_length $large_req_key { ~^[2-9][0-9]{6,}$ $binary_remote_addr; default ""; } limit_req_zone $large_req_key zone=bigpost:10m rate=2r/s; location / { limit_req zone=bigpost burst=3 nodelay; proxy_pass http://backend; }这段配置对
$request_length ≥ 2MB的请求按 IP 限速,防止单个来源持续投递大包。
补充建议:区分合法上传与恶意填充
- 合法大文件上传通常有明确路径(如
/upload)、带multipart/form-data头、UA 合理、且$body_bytes_sent较大; - 恶意填充常出现在通用接口,Body 内容无结构(如纯随机字符)、UA 异常(空或扫描器特征)、响应极短;
- 可配合
$content_length对比:若$content_length声明很大但$request_length小很多,可能是慢速攻击;若两者接近且极大,则是实打实的大载荷。
不复杂但容易忽略。

















