nginx无法直接过滤http协议版本,但可通过四类间接方式实现:一、用if ($host = "") { return 400; }拦截无host头的http/1.0请求;二、依赖nginx内置解析失败机制自动拒收非法协议如http/3.0;三、通过禁用tls旧版本或移除http2参数限制http/2/3;四、用map匹配请求行中的伪造协议字符串并返回400。

Nginx 本身不提供直接过滤或拒绝特定 HTTP 协议版本(如 HTTP/0.9、HTTP/1.0、HTTP/2 降级请求等)的原生指令。它默认兼容 HTTP/1.0、HTTP/1.1 和 HTTP/2(启用后),且对协议版本的识别和协商由底层网络层(如 OpenSSL、HTTP/2 状态机)自动处理,不可通过 if、map 或 limit_except 等常规配置主动拦截或校验 $server_protocol 的值。
但你可以通过以下间接、务实、可落地的方式实现“过滤非法 HTTP 版本”的安全目标:
一、强制只允许 HTTP/1.1 及以上(禁用 HTTP/1.0 和更旧版本)
HTTP/1.0 缺乏 Host 头、持久连接等关键特性,易被滥用(如慢速攻击、Host 头绕过)。虽然 Nginx 不会因版本低而拒接,但可通过拒绝无 Host 头的请求来实质拦截绝大多数 HTTP/1.0 请求(因其常省略 Host):
server {
listen 80;
server_name _;
if ($host = "") {
return 400;
}
# 其他配置...
}
✅ 说明:HTTP/1.0 客户端若未显式发送
Host:头,$host为空;而 HTTP/1.1+ 强制要求 Host 头(RFC 7230)。该方式不依赖协议字符串,稳定有效。
二、禁止非标准或实验性协议标识(如伪造的 HTTP/3.0、HTTP/999)
Nginx 解析请求行时,若协议字段非法(如 GET / HTTP/abc),会直接返回 400 Bad Request,无需额外配置。你只需确保:
- 不自定义
error_page 400覆盖默认行为; - 日志中开启
error_log ... info;,便于观察类似日志:client sent invalid request line: "GET / HTTP/3.0" while reading client request line
⚠️ 注意:这不是“过滤”,而是 Nginx 内置的协议解析失败保护机制,已默认生效。
三、限制 TLS 层协议以间接控制 HTTP/2 和 HTTP/3
HTTP/2 和 HTTP/3 依赖 TLS 协商:
-
禁用 HTTP/2:移除
http2参数listen 443 ssl; # 不加 http2 → 只走 HTTP/1.1 over TLS
禁用 HTTP/3:不配置
quic监听,且确保未启用ngx_http_v3_module(Nginx 官方尚未默认集成 HTTP/3)-
禁用老旧 TLS 版本(影响协议协商能力):
ssl_protocols TLSv1.2 TLSv1.3; # 禁用 TLSv1.0/TLSv1.1,间接阻止其承载的 HTTP/1.1 降级滥用
四、用 map + if 拦截明显伪造的协议字符串(仅作补充)
虽然 $server_protocol 变量在 if 中不可用于条件判断(Nginx 报错 nginx: [emerg] "if" directive is not allowed here),但你可以借助 map 配合请求行正则提取,再用 if 判断(需放在 server 块顶层):
map $request $bad_protocol {
~*^GET\s+/.*\s+HTTP/0\.9 1;
~*^GET\s+/.*\s+HTTP/0\.0 1;
~*^GET\s+/.*\s+HTTP/[4-9]\.[0-9] 1;
default 0;
}
server {
if ($bad_protocol) {
return 400 "Unsupported HTTP version";
}
# ...
}
✅ 说明:该方式匹配请求行末尾协议标识,能捕获
GET / HTTP/0.9或GET / HTTP/42.0等明显异常;但无法匹配 POST 请求头后的协议字段(因$request只含首行)。
不复杂但容易忽略











