跳转到内容

PHP目录遍历漏洞

来自代码酷

PHP目录遍历漏洞[编辑 | 编辑源代码]

目录遍历漏洞(Directory Traversal,也称路径遍历漏洞)是PHP安全编程中常见的一种漏洞,攻击者通过构造恶意输入访问服务器上本应受限的文件或目录。这种漏洞通常出现在文件操作函数未正确过滤用户输入的情况下,可能导致敏感数据泄露、文件篡改或服务器入侵。

基本概念[编辑 | 编辑源代码]

目录遍历漏洞的核心问题是程序未对用户提供的路径进行充分验证,导致攻击者可以通过特殊字符(如`../`)跳出预期的目录范围,访问上级目录或其他敏感路径。例如:

  • 预期访问:`/var/www/uploads/userfile.txt`
  • 攻击者构造路径:`../../../etc/passwd`,最终访问系统密码文件

漏洞原理[编辑 | 编辑源代码]

graph LR A[用户输入文件名] --> B{是否过滤../?} B -->|否| C[拼接完整路径] C --> D[读取敏感文件] B -->|是| E[安全访问]

数学表达上,漏洞产生的原因是路径拼接时未对输入进行规范化处理: 最终路径=基础路径+用户输入用户输入包含..

漏洞示例[编辑 | 编辑源代码]

基础示例[编辑 | 编辑源代码]

以下是一个存在漏洞的PHP代码片段:

<?php
$file = $_GET['file']; // 用户可控输入
$base_path = '/var/www/uploads/';

// 直接拼接路径 - 危险!
readfile($base_path . $file);
?>

攻击方式:

http://example.com/script.php?file=../../../etc/passwd

输出结果: 显示系统的`/etc/passwd`文件内容

安全修复方案[编辑 | 编辑源代码]

使用`realpath()`和`basename()`组合验证:

<?php
$file = $_GET['file'];
$base_path = '/var/www/uploads/';

// 规范化路径并检查是否在基础目录内
$real_path = realpath($base_path . basename($file));
if (strpos($real_path, realpath($base_path)) === 0) {
    readfile($real_path);
} else {
    die("非法访问!");
}
?>

进阶防护技术[编辑 | 编辑源代码]

1. 白名单验证[编辑 | 编辑源代码]

只允许特定扩展名的文件:

$allowed_ext = ['jpg', 'png', 'txt'];
$ext = pathinfo($file, PATHINFO_EXTENSION);
if (!in_array($ext, $allowed_ext)) {
    die("文件类型不允许");
}

2. PHP内置函数防护[编辑 | 编辑源代码]

使用`SplFileInfo`类:

$file = new SplFileInfo($base_path . $file);
if ($file->getRealPath() && 
    strpos($file->getRealPath(), realpath($base_path)) === 0) {
    // 安全操作
}

真实案例[编辑 | 编辑源代码]

案例1:CMS系统漏洞(2018年) 某流行CMS的1.2.3版本中,文件下载功能未过滤`../`,导致攻击者能下载配置文件`config.inc.php`,获取数据库凭证。

攻击payload:

/download.php?file=../../config/config.inc.php

案例2:云存储服务漏洞(2020年) 某云服务API在处理文件路径时,URL解码后未验证路径,允许这样的攻击:

GET /api/file?name=%2e%2e%2f%2e%2e%2fkey.pem
(解码后:../../key.pem)

防御总结[编辑 | 编辑源代码]

危险做法 安全替代方案
使用`realpath()`+目录前缀检查
白名单验证文件类型
使用`basename()`或`SplFileInfo`

延伸阅读[编辑 | 编辑源代码]

  • 永远不要仅依赖客户端验证
  • 考虑使用chroot环境限制PHP访问范围
  • 定期进行安全审计,使用工具如`phpstan`检测潜在漏洞

通过理解目录遍历漏洞的原理和防护方法,开发者可以显著提高PHP应用的安全性。记住:所有用户输入都不可信,必须进行严格验证和过滤。