<!-- title: directory-traversal -->
目录遍历与敏感信息泄露详解:原理、利用与防御
一、漏洞原理
目录遍历(Path Traversal,又称目录穿越)是指应用在处理文件路径时允许用户输入跳转序列(../),从而越出预设目录、读取服务器上任意文件的漏洞。典型场景是"文件下载/预览"功能:download.php?file=report.pdf——如果 file 参数未校验,攻击者传 file=../../../../etc/passwd 就能下载系统任意文件。
它与文件包含(LFI)是近亲:LFI 的落脚点是"被包含后执行",目录遍历的落脚点是"被读取后泄露";两者常共享同一类漏洞代码和同一套 ../ 跳转手法,防御思路也同源。
而"敏感信息泄露"(Sensitive Data Disclosure)是更广义的一类问题:除了路径遍历读文件,还包括 GitHub 仓库里提交了密码、接口响应返回了过多字段、报错页面泄露堆栈与路径、备份文件(web.zip、.sql 转储)被直接放在 Web 目录可下载等。实战中大量"入侵"并非靠高大上的漏洞,而是靠这些散落各处的"钥匙"。把两者放在一起讲,是因为它们共享同一条防御哲学:默认最小暴露。
二、示例代码
以下是一个存在目录遍历的下载接口(虚构站点 example.com):
<?php
// download.php —— 提供附件下载
$file = $_GET['file'];
readfile("/var/www/example.com/files/" . $file); // 致命点:直接拼接后读取
?>攻击者请求 download.php?file=../../../../etc/passwd,../ 逐层跳转后实际读取的是 /etc/passwd。修复后的安全写法是"白名单 ID + realpath 双保险":
<?php
// 安全版:白名单优先,realpath 校验兜底
$allowed = ['report2026' => 'report-2026.pdf', 'manual' => 'user-manual.pdf'];
$key = $_GET['doc'] ?? '';
if (!isset($allowed[$key])) { http_response_code(404); exit('文件不存在'); }
$base = realpath('/var/www/example.com/files');
$target = realpath($base . '/' . $allowed[$key]);
// realpath 解析掉所有 ../ 后,必须仍位于基础目录内
if ($target === false || !str_starts_with($target, $base . DIRECTORY_SEPARATOR)) {
http_response_code(403);
exit('非法路径');
}
readfile($target);
?>三、三种典型 Payload(教学演示)
1. 相对路径跳转(../ 系列)
?file=../../../../etc/passwd
?file=..\..\..\..\windows\win.ini (Windows)
?file=....//....//etc/passwd (过滤 ../ 时的双写绕过)
?file=%2e%2e%2f%2e%2e%2fetc%2fpasswd (URL 编码绕过)从单写、双写到 URL 编码,攻防围绕"过滤是否可绕过"展开。这条 Payload 家族的教学意义:靠正则过滤跳转序列注定被动,用 realpath 类"解析后校验"才是釜底抽薪。
2. 绝对路径注入
?file=/etc/passwd
?file=C:\windows\win.ini若代码是直接拼接(无目录前缀)或拼接时未校验"必须以预期前缀开头",攻击者可以直接给绝对路径。它提示防御者:既要防"跳出去",也要防"直接指进去"。
3. 常见敏感文件字典(泄露探测)
对 Web 根目录的直接探测同样是高频泄露源,公开教材中常见的探测清单包括:
/.env (框架环境配置:数据库密码、密钥)
/backup.zip、/dump.sql
/debug、/actuator、/server-status
/composer.json、/package.json、/.svn/entries这条"清单"正是自动化扫描器的种子字典,也是本站防火墙规则封锁 .env、.git 等路径的原因——防御者应当用同一份清单反向检查自己。
四、防御建议
- 白名单优先:下载/读取类功能用"逻辑 ID → 服务端路径"映射,用户输入永远不参与路径拼接(与文件包含同一处方药)
- realpath 后校验前缀:无法白名单时,把拼接结果
realpath()归一化,再校验其必然位于允许的基准目录之内 - 容器与进程权限兜底:Web 进程以低权限账户运行、文件系统只读化、敏感配置走环境变量注入而非文件,即使遍历成立也读不到高价值内容
- 发布前做"暴露面自查":用扫描器字典反向扫自己的站点,确保
.env、备份文件、调试端点、源码清单不存在于 Web 可访问范围;CI 里加一步"敏感文件存在性检查" - 报错不泄密:生产环境关闭详细错误输出,统一友好错误页,避免堆栈中的绝对路径、SQL 语句、框架版本成为攻击者的路标
- 仓库卫生:
.gitignore覆盖密钥与配置文件,历史提交定期审计(一旦密钥进过 git 历史,视为已泄露并立即轮换)
五、总结
目录遍历与信息泄露提醒我们一件事:攻击者拿到的不一定是"漏洞利用成功",往往只是"你多给了"。一个没删的备份包、一行没关的报错、一个没校验的下载参数,足够拼出整条入侵路径。防御的口诀依然是那三个词:白名单、realpath 校验、最小暴露——再配上一份"以攻击者视角反扫自己"的自觉,泄露类风险即可压到最低。