PHP 5.3.4起默认禁用%00截断,但magic_quotes_gpc=Off时旧逻辑仍可能被利用;需在include前用str_replace(chr(0), '', $input)清除空字节,并结合basename+白名单校验、open_basedir限制及禁用高危函数等多层防护。

PHP 5.3.4 是一个关键分水岭版本:它默认禁用了 %00(空字节)截断,但仅在 magic_quotes_gpc=Off 且未显式过滤时,旧版逻辑残留仍可能被利用。防范重点不是“升级就万事大吉”,而是堵住路径拼接中空字节进入文件系统前的通道。
立即生效的代码层过滤
在接收用户输入后、传给 include 前,必须清除所有空字节:
- 用
str_replace(chr(0), '', $input)直接移除,这是最简洁可靠的写法 - 避免只用
trim()或正则/\x00/替换而忽略多字节编码场景,chr(0)更明确 - 若参数需保留原始语义(如日志记录),过滤应在路径构造环节做,而非展示环节
路径规范化 + 白名单双重校验
空字节只是绕过手段,根本问题在于路径不可控。应组合使用:
- 先用
basename($input)提取纯文件名,剥离所有路径符号(../、/etc/、%00后的干扰部分全失效) - 再用白名单数组映射合法值:
$whitelist = ['home' => '/var/www/inc/home.php', 'about' => '/var/www/inc/about.php']; - 只允许用户传入键名(如
page=home),查表取绝对路径,不拼接、不解析
php.ini 级别加固(针对 5.3.4 及后续)
即使代码有疏漏,环境配置也能兜底:
立即学习“PHP免费学习笔记(深入)”;
- 确认
allow_url_include = Off—— 阻断远程包含,也削弱多数伪协议利用链 - 设置
open_basedir限定可访问目录,例如open_basedir = /var/www/html:/tmp - 禁用高危函数:
disable_functions = show_source, system, exec, shell_exec, passthru(虽不防包含本身,但能限制后续RCE)
审计与替代方案
对存量代码快速排查:
- 全局搜索
include($_、require($_、include_once($_等模式,定位所有动态包含点 - 凡非白名单场景,优先重构为静态包含或类自动加载(PSR-4),彻底消除运行时路径拼接
- 若业务强依赖动态模板,改用模板引擎(如 Twig)并关闭其
eval模式,比裸include安全得多



















