PHP 8.0 防止文件包含漏洞的核心是禁用动态路径拼接,强制采用白名单映射或 basename+realpath 双重校验,并关闭 allow_url_include、拦截伪协议,结合 Psalm 污点分析主动识别风险。

PHP 8.0 本身不提供自动过滤机制,防止 include 文件包含漏洞的关键,在于彻底杜绝用户输入直接参与文件路径构造。include、require 等函数一旦拼接了未校验的 $_GET、$_POST 或其他可控参数,就极易触发 LFI(本地文件包含)甚至 RCE(远程代码执行)。PHP 8.0 移除了 allow_url_include 和 assert() 字符串执行等危险机制,但对开发者自己写的不安全 include 调用毫无防护作用。
严格禁止动态路径拼接
这是最根本的防线。任何形如 include($_GET['file'] . '.php') 或 require 'modules/' . $_POST['action'] . '.inc' 的写法都必须删除或重构。
- 改用白名单映射:将合法值硬编码为键值对,只允许从预设集合中选取
- 示例:
$allowed = ['dashboard' => 'admin/dashboard.php', 'profile' => 'user/profile.php']; $page = $_GET['page'] ?? 'dashboard'; include $allowed[$page] ?? die('Invalid page'); - 绝对不要用字符串拼接、正则替换、黑名单过滤(如删 ../)来“修复”路径——这些方式在多层编码、空字节、大小写绕过等场景下全部失效
路径规范化与真实路径校验
若业务逻辑确实需要读取用户指定子目录下的文件(如模板、配置),必须做两级验证:
修复 Core bailout 状态损坏安全问题,以及 BZ2、DOM、PDO、Opcache/JIT 内存与执行错误,改进 Unicode 字素处理、URL 解析、TLS 流状态、信号分发及会话错误处理。
- 先用
basename()提取文件名,剥离所有路径信息;再拼接进固定根目录,例如:$root = __DIR__ . '/templates/'; $file = basename($_GET['tpl']); include $root . $file . '.php'; - 再用
realpath()获取真实路径,并检查是否仍在预期目录内:$full = realpath($root . $file . '.php'); if (!$full || strpos($full, $root) !== 0) { die('Access denied'); } - 注意:realpath 对不存在的文件返回 false,需提前判断
禁用危险协议与外部加载
PHP 8.0 已移除 allow_url_include 指令,但为防低版本兼容或配置残留,仍需确认其关闭:
立即学习“PHP免费学习笔记(深入)”;
- 在 php.ini 中确保:
allow_url_include = Off(默认即为 Off) - 检查运行时配置:
var_dump(ini_get('allow_url_include'));应返回空字符串或 '0' - 避免使用
php://filter、data://、phar://等伪协议参与 include,这类调用即使路径可控,也应在代码层主动拦截
用 Psalm 等工具主动发现隐患
静态分析能提前暴露潜藏的危险模式:
- 在 Psalm 配置中启用污点分析:
<taintanalysis></taintanalysis> - 标记用户输入源(如
think\Request::get()或$_GET)为污染源 - 当检测到污染数据流入
include、require、file_get_contents等敏感函数时,Psalm 会明确报出 TaintedInput 错误 - 配合 CI/CD 流程,在合并前阻断含高危调用的代码提交


















