
一、文件包含漏洞是什么
文件包含漏洞源于程序在包含文件时,文件路径由用户输入控制,且没有做严格校验。攻击者可以通过构造特殊的路径参数,让程序去读取或执行本不该访问的文件。
典型的存在漏洞的代码逻辑是:根据 URL 参数决定加载哪个页面文件。如果参数没做校验,攻击者就能操纵这个路径。
二、两类文件包含及其危害
1. 本地文件包含(LFI)
攻击者让程序包含服务器上的本地文件。危害包括:
- 读取敏感文件——配置文件(可能含数据库密码)、系统账号文件、源码文件;
- 配合日志投毒提权——先想办法把恶意代码写进服务器日志,再通过包含日志文件来执行代码;
- 读取上传的临时文件——结合上传功能实现代码执行。
2. 远程文件包含(RFI)
如果服务器配置允许(allow_url_include 开启),攻击者可以让程序加载外部服务器上的文件。这就等于直接把恶意代码引进来执行,危害等同于 RCE(远程代码执行)。
好消息是:现代 PHP 配置中该选项默认关闭,所以 RFI 比 LFI 少见得多。
三、WAF 的检测思路
① 路径穿越符检测
LFI 攻击的典型特征是使用 ../ 向上跳转目录。WAF 会检测各种变形写法:
| 变形方式 | 示例形态 |
|---|---|
| 标准形式 | 连续的上级目录符号 |
| URL 编码 | 把符号编码为 %2e%2e%2f 等形式 |
| 双重编码 | 对编码结果再编码一次 |
| Unicode 编码 | 使用 Unicode 表示符号 |
| 混合形式 | 部分编码部分明文 |
WAF 需要在解码后检测,才能识别这些绕过手法。
② 敏感路径识别
除了路径穿越符,还可以直接识别攻击者想访问的目标文件路径:
- 系统账号文件路径;
- Web 配置文件路径;
- 环境变量文件、密钥文件;
- 常见的日志文件路径。
③ 危险伪协议识别
PHP 提供了一些「伪协议」,可以被文件包含漏洞利用:
| 伪协议类型 | 用途 | 风险 |
|---|---|---|
| 读取输入流 | 直接读取请求体作为代码 | 可执行任意代码 |
| 数据协议 | 把数据当作文件内容 | 可执行任意代码 |
| 压缩协议 | 读取压缩包内文件 | 可配合上传利用 |
| 其他流包装器 | 各种输入输出流 | 视具体协议而定 |
WAF 会检测参数中是否出现这些协议头,出现即拦截。
④ 外部 URL 识别
针对 RFI,检测参数中是否包含外部 URL。因为正常的文件包含参数通常是相对路径或本地路径,很少是完整的 HTTP 地址。
四、WAF 检测的难点
难点一:正常业务也可能用路径参数
很多 CMS 和框架确实用参数来指定加载的模板或页面。比如 ?page=about 这种写法本身是正常的。WAF 需要区分「正常的页面名」和「恶意的路径穿越」,通常会通过限制参数格式来实现——只允许字母数字,拒绝斜杠和点号。
难点二:日志投毒等间接手法
这种情况下,第一次的「投毒」请求看起来可能完全无害(就是访问一个带特殊 UA 的页面),第二次的「包含」请求才是攻击。WAF 需要额外规则来识别「包含日志文件路径」这类特征。
难点三:编码混淆
攻击者会用多层编码绕过检测。WAF 的解码层数和顺序如果不够,就可能漏检。这是持续对抗的过程。
五、站长该怎么做
① 开启相关防护规则
确保 WAF 的文件包含与路径穿越防护规则处于开启状态。这是基础规则的一部分,通常默认开启。
② 用自定义规则限制参数格式
如果业务确实有「用参数指定页面」的需求,用自定义规则限定参数格式:
- 只允许字母、数字、连字符、下划线;
- 拒绝包含点号、斜杠、冒号等特殊字符;
- 用白名单枚举允许的页面名,这是最安全的做法。
③ 代码层修复
流量层防护之外,代码层必须做修复:
- 避免用用户输入直接拼路径——这是根本原则;
- 使用白名单映射——把参数映射到固定的文件列表,而不是直接拼接路径;
- 过滤路径字符——移除
../、..\等穿越符; - 限制包含范围——用
open_basedir限制 PHP 可访问的目录; - 关闭危险配置——确保
allow_url_include处于关闭状态。
六、小结
WAF 对文件包含漏洞有较好的检测能力,通过路径穿越符、敏感路径、危险伪协议、外部 URL四类特征识别攻击。但面对编码混淆和日志投毒等手法需要持续更新规则。代码层应遵循「不用用户输入拼路径、改用白名单映射」的原则,从根本上消除漏洞。
