文件包含漏洞是什么
文件包含指程序在运行期根据输入拼接路径去加载文件。当这个输入由用户可控时,就可能出现两类问题:本地文件包含(LFI)让攻击者读取服务器上的任意可读文件,远程文件包含(RFI)则允许加载外部地址的内容,直接演变为代码执行。RFI 依赖 allow_url_include 这类开关,现代 PHP 默认关闭,但 LFI 依然常见,配合日志文件、会话文件与 phar 包装器可以进一步升级危害。
基本信息
| 常见载体 | PHP 的 include/require、模板引擎动态路径、插件与模块加载 |
|---|---|
| 类型 | LFI 本地文件包含、RFI 远程文件包含 |
| 危害 | 读取配置与凭据文件、加载可执行内容、配合包装器升级 |
| 根治思路 | 用固定映射表替代自由路径拼接,关闭远程包含能力 |
典型使用场景
- 重构遗留代码:把 page=xxx 形式的动态包含改为白名单映射
- 代码评审时搜索存在路径拼接的包含语句,检查输入来源
- 模板引擎配置审查:确认模板路径不含用户可控成分
- 插件与模块加载机制评估:第三方插件目录是否可被写入
- 上线前确认远程包含与危险包装器均处于关闭状态
安全改造示例(PHP)
安全改造示例(PHP)
$pages = ['home' => 'home.php', 'about' => 'about.php'];
$key = $_GET['page'] ?? 'home';
// 白名单校验:不在映射表中的键一律拒绝
if (!isset($pages[$key])) {
http_response_code(404);
exit;
}
// 只拼接映射表中的固定值,用户输入不进入路径
include __DIR__ . '/pages/' . $pages[$key];防护手段对比
| 手段 | 有效性 | 说明 |
|---|---|---|
| 黑名单过滤 ../ 与 http:// | 低 | 编码变形与包装器可绕过 |
| 映射表白名单 | 高 | 输入只用于查表,不进入路径 |
| 关闭 allow_url_include | 中 | 只挡住远程包含这一类 |
| 目录权限收敛 | 辅助 | 降低被包含文件的危害上限 |
现代 PHP 默认关闭 allow_url_include,远程包含已较少见;但仍要关注 phar://、data:// 等包装器与日志包含链路,它们能把单纯的读取升级为代码执行。
用黑名单过滤 ../ 与协议前缀的写法容易被编码与包装器绕过,改造时优先换成映射表,而不是继续加固过滤规则。