最有效防御是全局拦截含%00的请求:if ($request_uri ~ "%00") { return 403; },须置于server块顶层;需同步禁用上传目录PHP执行、设cgi.fix_pathinfo=0、升级Nginx至1.20+或启用ModSecurity。

直接拦截含 %00 的请求是最有效、最轻量的防御方式,但“完美防御”不单靠一条规则——它需要在请求解析早期切断空字节路径,并同步阻断其可能触发的后续逻辑错位(比如 FastCGI 路径拼接、上传文件被误执行等)。
全局拦截原始 URI 中的 %00
空字节攻击依赖的是未解码的原始请求串,所以必须用 $request_uri(而非已解码的 $uri)匹配:
- 在 server 或 http 块顶层添加:
if ($request_uri ~ "%00") { return 403; } - 这条规则必须放在所有 location 块之前,避免被正则 location 绕过或延迟执行
- 不要写在 location 内部,否则可能因 Nginx 的 if 执行上下文导致意外跳过
阻断空字节参与的路径构造变体
攻击者常组合空字节与其他编码(如 %00.php、.jpg%00/.php),需补充覆盖常见模式:
- 拒绝含
%00后紧跟可执行扩展名的请求:if ($request_uri ~ "%00.php") { return 403; } - 拦截形如
/a.jpg%00/b.php这类嵌套结构:if ($request_uri ~ "%00[/\]") { return 403; } - 对上传目录做硬性隔离:在对应 location 中禁用 PHP 解析,不依赖后缀判断
location ^~ /upload/ { location ~ .php$ { deny all; } }
切断 Nginx 与后端的路径语义分歧
空字节本身不是漏洞根源,真正危险在于 Nginx 和 PHP-FPM 对同一 URI 解析不一致。需从参数传递层加固:
- 强制使用确定性脚本路径:
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
禁用$request_filename,防止空字节污染拼接结果 - PHP 层必须设
cgi.fix_pathinfo = 0,关闭自动路径补全,让 PHP 只执行真实存在的 .php 文件 - 在 PHP 处理块中加兜底校验:
try_files $fastcgi_script_name =404;,确保文件物理存在才转发
配合基础输入规范化与版本升级
空字节常伴随其他畸形编码出现,建议一并处理:
- 拒绝非法十六进制编码(如
%xz、%g1):if ($request_uri ~ "%[^0-9A-Fa-f]{2}") { return 400; } - 关闭潜在歧义特性:
merge_slashes off;防止//合并干扰路径匹配underscores_in_headers on;避免请求头干扰解析 - 升级至 Nginx 1.20+ 版本,原生修复了多个 URI 解析边界问题;若无法升级,启用 ModSecurity + OWASP CRS 规则集作为补充防线


















