PHP文件包含漏洞本质是用户可控输入直接拼接进include等函数,导致任意文件读取或执行;修复必须采用白名单映射、禁用危险配置、运行时拦截与工具验证四重措施。

PHP 8.1 中变量可控导致的文件包含漏洞(如 include $_GET['file'])本质是**路径拼接未校验、用户输入直接进入包含函数**,属于典型的代码级漏洞。它不依赖 PHP 解释器缺陷,因此升级 PHP 版本无法修复——必须从代码逻辑和运行时防护两方面入手。
一、立即阻断:禁用危险配置与函数
这是最快速有效的临时缓解措施,尤其适用于暂无法修改代码的生产环境:
- 在
php.ini中关闭远程包含能力:
allow_url_fopen = Off 且 allow_url_include = Off(二者缺一不可,仅关其一仍可能被绕过) - 禁用高危函数(需配合
disable_functions):
disable_functions = include, include_once, require, require_once, eval, assert, system, exec, shell_exec, passthru - 重启 PHP-FPM 或 Apache,确认生效(可通过
phpinfo()页面检查)
二、代码层修复:白名单映射 + 类型约束
PHP 8.1 提供了更严格的类型系统和枚举支持,应充分利用,避免“黑名单过滤”这类易绕过的方式:
修复 Core bailout 状态损坏安全问题,以及 BZ2、DOM、PDO、Opcache/JIT 内存与执行错误,改进 Unicode 字素处理、URL 解析、TLS 流状态、信号分发及会话错误处理。
- 将动态路径转为预定义键值映射,例如:
$pages = ['home' => 'tpl/home.php', 'about' => 'tpl/about.php'];
$page = $_GET['page'] ?? 'home';
if (array_key_exists($page, $pages)) { include $pages[$page]; } - 使用 PHP 8.1 枚举限定合法值:
enum Page: string { case Home = 'home'; case About = 'about'; }
$page = Page::tryFrom($_GET['page'] ?? '');
if ($page) { include "tpl/{$page->value}.php"; } - 对字符串路径做双重校验:
if (preg_match('/^[a-z0-9_]+\.php$/', $filename) && file_exists("safe_dir/$filename")) { include "safe_dir/$filename"; }
三、运行时加固:拦截可疑包含行为
即使代码已修复,也建议加一层运行时防护,捕获异常调用模式:
立即学习“PHP免费学习笔记(深入)”;
- 在入口文件(如
index.php)顶部注册自动加载或钩子:
function safe_include(string $file): void {
if (!str_starts_with($file, 'safe_dir/') || !is_file($file)) {
error_log("Suspicious include attempt: $file");
http_response_code(403);
exit;
}
include $file;
} - 结合 PHP 8.1 的
#[\ReturnTypeWillChange]注解,确保魔术方法(如__autoload)类型一致,防止因类型错误引发的包含逻辑跳过
四、扫描与验证:用工具确认修复效果
修复后务必验证是否真正消除风险:
- 用 PHP Insights 扫描项目:
vendor/bin/phpinsights --min-security=100,重点关注ForbiddenSecurityIssues规则是否报告include/require直接使用用户输入 - 手动测试典型绕过 payload:
?file=../../etc/passwd、?file=php://filter/read=convert.base64-encode/resource=index.php、?file=data:text/plain,<?php phpinfo();?>,确认全部返回 403 或空白响应 - 检查日志中是否仍有
suspicious include attempt记录,若有说明仍有遗漏点


















