Nginx不解析请求体Gzip,防范畸形压缩攻击需通过限制请求头/体大小、缩短超时、拦截非法Content-Encoding头三道机制提前拒绝。

Nginx 本身不直接解析或校验请求体的压缩编码(如 Gzip),它默认将解压工作交给上游应用(如 PHP、Node.js)或依赖 ngx_http_gunzip_module(仅用于响应解压)。但携带畸形 Gzip 头部的请求属于典型的 Slowloris 类或协议层 DoS 攻击,其目的不是正常传输数据,而是耗尽 Nginx 的连接缓冲区、内存或 worker 进程资源。
要识别并拦截这类攻击,关键不是“检测 Gzip 是否合法”,而是限制异常压缩行为带来的资源消耗,并通过配置提前拒绝可疑请求。以下是可落地的配置策略:
启用并收紧请求体与头部的缓冲和超时控制
畸形压缩常表现为:极小的 Content-Encoding 声明 + 超大/畸形的请求体、缓慢发送、或伪造的 gzip header(如 magic bytes 1f 8b 后接无效数据)。Nginx 可在协议解析阶段就切断这类请求:
http {
# 严格限制请求头大小(防 oversized headers + fake gzip hints)
client_header_buffer_size 1k;
large_client_header_buffers 2 1k;
# 限制请求体大小(防恶意上传带伪造 gzip header 的巨量垃圾数据)
client_max_body_size 2m; # 根据业务调低,如 API 接口通常 ≤ 10MB
# 缩短读取请求头和请求体的超时,快速淘汰慢速/畸形连接
client_header_timeout 5s;
client_body_timeout 8s;
# 禁用对客户端声称的 gzip 编码做自动处理(Nginx 默认不处理 request body 的 gzip)
# → 避免误启 gunzip 模块导致解析崩溃(除非你明确启用且信任来源)
# 注意:gunzip on; 仅应在可信内网代理场景启用,公网入口务必关闭
}✅ 实际效果:当攻击者发送一个
Content-Encoding: gzip但实际 payload 是乱序字节或截断 gzip 流时,Nginx 在读取 body 超过client_body_timeout或超出client_max_body_size后直接返回400 Bad Request或413 Payload Too Large,不交由后端处理。
拦截明显伪造的 Content-Encoding 请求头
多数畸形压缩攻击会滥用 Content-Encoding 字段(如重复声明、拼写错误、或搭配不支持的方法)。可用 map + if 提前拦截:
http {
map $http_content_encoding $bad_encoding {
default 0;
"~*(?:x-gzip|compress|deflate\s*,\s*gzip|gzip\s*,\s*gzip)" 1; # 多重/非法组合
"~*(?:bogus|fake|broken)" 1;
"~*\x00\x01\x02" 1; # 二进制开头(常见于 raw gzip magic bypass 尝试)
}
server {
if ($bad_encoding) {
return 403;
}
}
}⚠️ 注意:if 在 server 块中可用,但避免放在 location 外全局使用;优先用 map 归类后再统一处理。
禁用非必要编码类型,显式只允许已知安全值
如果业务只接受 identity 或明确需要 gzip(且由可信前端注入),可白名单化:
location /api/ {
if ($http_content_encoding !~ ^(gzip|identity|)$) {
return 403;
}
# 后续 proxy_pass 或 fastcgi_pass...
}补充:日志中捕获可疑请求用于分析
添加自定义日志字段,便于后续筛查异常编码行为:
log_format security '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_content_encoding" "$http_content_length" '
'"$request_time"';
access_log /var/log/nginx/security.log security;查日志示例(发现高频 Content-Encoding: gzip 但 Content-Length 极小或为 0):
awk '$12 ~ /gzip/ && ($11 < 10 || $11 == "-")' /var/log/nginx/security.log | head -20
不复杂但容易忽略——真正起效的不是“识别 gzip 是否标准”,而是用超时、大小、头字段白/黑名单三道闸机,在请求进入业务逻辑前就让它止步。


















