Nginx返回400是因请求格式违法,如请求行非法、Host头缺失或含CRLF、URI未编码含空格、HTTP版本不识别等;需通过增强日志(如$request、$http_host)和error_log中的具体提示交叉分析,区分真实攻击与误报。

400 Bad Request 本身不是安全漏洞,而是 HTTP 协议层的语义错误反馈。Nginx 返回 400,通常意味着它在解析请求时发现格式违法——比如请求行非法、Host 头缺失或畸形、请求头超长、URI 未编码含空格/控制字符、HTTP 版本不识别等。这类响应在渗透测试中常被误判为“服务异常”,实则可能是攻击载荷被 Nginx 主动拦截的信号。
哪些日志字段能暴露畸形请求特征
Nginx 默认 access_log 不记录完整请求头,无法直接判断 400 原因。需主动增强日志结构:
- 在 http 或 server 块中定义自定义日志格式,捕获关键字段:
log_format debug_400 '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_host" "$request_uri" "$request_time" "$upstream_http_content_type"'; - 对返回 400 的 location 单独启用该格式:
location / { error_page 400 /400.html; access_log /var/log/nginx/400_debug.log debug_400 if=$is_400; } - 配合 map 指令标记 400 请求:
map $status $is_400 { 400 1; default 0; }
常见渗透载荷触发 400 的典型模式
攻击者常利用协议边界绕过 WAF,但 Nginx 会在解析阶段就拒绝以下请求:
- 畸形 Host 头:如 Host: evil.com\r\nX-Forwarded-For: 127.0.0.1 —— 包含 CRLF 的 Host 会被 Nginx 直接拒收,返回 400;
- 超长 URI 或请求行:GET /a*10000 会超出 large_client_header_buffers 单块限制,触发 400;
- 非法 HTTP 方法或版本:如 GOT / HTTP/2.0、GET / HTTP/1.00,Nginx 仅接受标准方法名与合法版本字符串;
- 空 Host 或缺失 Host(HTTP/1.1):HTTP/1.1 强制要求 Host 头,缺失即 400;Nginx 不会转发该请求到后端。
如何区分真实攻击与误报
单看 400 日志不足以定性攻击,需交叉验证:
- 检查 error_log 中是否伴随 client sent invalid request、client intended to send too large chunked body 等明确提示;
- 比对同一 IP 在短时间内是否集中出现不同畸形模式(如 Host 变形 + URI 编码混淆 + 方法篡改),高概率为扫描行为;
- 确认请求是否来自已知代理、爬虫 UA 或无 Referer 的裸请求——这类流量中 400 出现率天然偏高,但未必恶意。
防御建议:不止于调大缓冲区
盲目增大 client_header_buffer_size 和 large_client_header_buffers 可能掩盖问题,甚至放大风险:
- 将 client_header_timeout 设为 5s 内,防止慢速畸形头耗尽连接;
- 用 if ($host !~ ^[a-zA-Z0-9._-]+$) { return 400; } 主动过滤非法 Host;
- 对 API 路径启用严格 method 白名单:
limit_except GET POST HEAD { deny all; } - 在 upstream 场景下,确保 proxy_set_header Host $host 不带原始恶意 Host —— 应改用固定后端域名,避免透传污染。











