PHP目录遍历:路径迷宫中的安全密码
一、当PHP脚本遭遇"回头路":目录遍历的诞生
想象你正在浏览一个个人博客,点击"查看图片"按钮时,浏览器突然弹出了服务器的/etc/passwd文件——这不是电影特效,而是PHP目录遍历漏洞的经典场景。作为Web开发的"隐形陷阱",目录遍历因路径处理不当而产生,却能让攻击者轻易闯入服务器的"禁地"。
PHP的路径解析规则如同迷宫地图:../是"回头路"(上级目录),/是"十字路口"(根目录),而realpath()函数则是"导航仪",能将混乱的路径规整为清晰的路线。但如果开发者忽略了这些规则,迷宫的大门就会向攻击者敞开。
二、路径迷宫的构造:PHP如何被"反向导航"
1. 漏洞的核心:..符号的"回头杀"
PHP中,../是目录遍历的"钥匙"。当代码将用户输入直接拼接进路径时,..会触发"向上跳转"。例如:
// 危险示例:未过滤的路径拼接
$user_input = $_GET['path']; // 用户输入:../etc/passwd
$file = '/var/www/html/uploads/' . $user_input; // 拼接后:/var/www/html/uploads/../etc/passwd
// PHP解析为:/var/www/html/etc/passwd
include $file; // 直接读取系统文件
此时,即使/var/www/html/uploads目录下没有目标文件,..也会让路径"回头"到系统根目录,读取敏感信息。
2. 常见的"路径陷阱"场景
- 直接拼接用户输入:使用
include($_GET['file'])等函数时,未过滤路径参数。 - 文件上传功能:上传图片时,路径包含
../导致遍历到其他用户目录。 - 日志读取漏洞:通过
file_get_contents($_GET['log'])读取服务器日志,用户输入/var/log/auth.log即可获取系统登录记录。
三、真实漏洞案例:从CVE到日常开发陷阱
1. Discuz! X3.2的"回头路"漏洞
2018年,Discuz! X3.2被曝目录遍历漏洞(CVE-2018-19893)。攻击者通过构造路径forum/../config.inc.php,成功读取到数据库配置文件,导致大量用户数据泄露。该漏洞的根源在于论坛的文件包含函数未过滤..符号。
2. 小型CMS的"隐形密码"
某个人开发的博客系统中,文章封面上传功能存在隐患:
// 错误示例:未过滤的路径拼接
$upload_dir = './covers/';
$filename = $_POST['filename'] . '.jpg';
$path = $upload_dir . $filename; // 拼接路径
copy($_FILES['cover']['tmp_name'], $path); // 保存上传文件
若攻击者上传文件名../admin/config,则路径变为./covers/../admin/config.jpg,解析后为./admin/config.jpg。若该文件不存在,PHP会报错暴露路径;若存在,则可能读取到后台配置。
四、防御密码:筑牢路径安全的"防火墙"
1. 代码层面:用"白名单"锁死路径
规范化路径:使用realpath()去除..符号:
// 安全示例:规范化路径+白名单检查
$allowed_dir = '/var/www/html/uploads/'; // 允许访问的目录
$user_input = $_GET['path'];
$normalized_path = realpath($user_input); // 解析路径:/var/www/html/uploads/../etc/passwd → /var/www/html/etc/passwd
// 检查路径是否在白名单目录下
if (strpos($normalized_path, $allowed_dir) === 0) {
include $normalized_path; // 仅读取允许的文件
} else {
die('非法访问:路径不在允许范围内');
}
过滤危险字符:使用basename()仅保留文件名:
$safe_filename = basename($_GET['file']); // 过滤掉../等危险路径
include $allowed_dir . $safe_filename; // 拼接后仅保留上传目录下的文件
2. 服务器层面:双重保险
**配置`open_based

