DVWA文件上传高级源码分析详解
字数 1282 2025-08-10 20:35:57

DVWA文件上传高级源码分析详解

1. 源码解析

1.1 基本结构

<?php
if( isset( $_POST[ 'Upload' ] ) ) {
    // 文件上传处理逻辑
}
?>

这段代码首先检查是否有名为'Upload'的POST请求提交,这是文件上传的触发条件。

1.2 文件路径设置

$target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
$target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
  • DVWA_WEB_PAGE_TO_ROOT 是一个常量,表示网站根目录的路径
  • basename() 函数提取文件名部分,防止路径遍历攻击
  • 最终$target_path是完整的上传目标路径,如/var/www/html/hackable/uploads/filename.ext

1.3 文件信息提取

$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];  // 原始文件名
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1 );  // 文件扩展名
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];  // 文件大小
$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];  // 临时文件路径
  • strrpos() 找到文件名中最后一个.的位置
  • substr().后一位开始截取,得到文件扩展名

1.4 文件验证逻辑

if( ( strtolower( $uploaded_ext ) == "jpg" || strtolower( $uploaded_ext ) == "jpeg" || strtolower( $uploaded_ext ) == "png" ) 
    && ( $uploaded_size < 100000 ) 
    && getimagesize( $uploaded_tmp ) ) {
    // 验证通过后的处理
}

验证条件包括:

  1. 扩展名必须是jpg/jpeg/png(不区分大小写)
  2. 文件大小小于100KB(100000字节)
  3. getimagesize()验证文件确实是有效的图片文件

1.5 文件移动处理

if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {
    echo '<pre>Your image was not uploaded.</pre>';
} else {
    echo "<pre>{$target_path} succesfully uploaded!</pre>";
}
  • move_uploaded_file() 将临时文件移动到目标位置
  • 该函数会自动检查文件是否是通过HTTP POST上传的合法文件

2. 关键函数详解

2.1 basename()

string basename ( string $path [, string $suffix ] )
  • 返回路径中的文件名部分
  • 可以防止路径遍历攻击
  • 示例:
    basename("/var/www/html/test.php"); // 返回 "test.php"
    basename("/var/www/html/test.php", ".php"); // 返回 "test"
    

2.2 strrpos()

int strrpos ( string $haystack , string $needle [, int $offset = 0 ] )
  • 返回字符串中最后一次出现的位置
  • 用于查找文件名中最后一个.的位置
  • 示例:
    strrpos("example.jpg", "."); // 返回 7
    

2.3 substr()

string substr ( string $string , int $start [, int $length ] )
  • 返回字符串的子串
  • 用于提取文件扩展名
  • 示例:
    substr("example.jpg", strrpos("example.jpg", ".") + 1); // 返回 "jpg"
    

2.4 strtolower()

string strtolower ( string $string )
  • 将字符串转换为小写
  • 用于统一比较文件扩展名
  • 示例:
    strtolower("JPG"); // 返回 "jpg"
    

2.5 getimagesize()

array getimagesize ( string $filename [, array &$imageinfo ] )
  • 获取图像大小及相关信息
  • 可以验证文件是否为真实图片
  • 返回数组包含宽度、高度、类型等信息

2.6 move_uploaded_file()

bool move_uploaded_file ( string $filename , string $destination )
  • 将上传的文件移动到新位置
  • 会自动检查文件是否是通过HTTP POST上传的合法文件
  • 比普通的rename()更安全

3. 安全分析

3.1 防护措施

  1. 文件类型验证

    • 检查扩展名(jpg/jpeg/png)
    • 使用getimagesize()验证文件内容
  2. 文件大小限制

    • 限制为100KB以内
  3. 路径安全

    • 使用basename()防止路径遍历

3.2 潜在绕过方式

  1. 双扩展名攻击

    • shell.php.jpg可能绕过扩展名检查
  2. 修改Content-Type

    • 伪造图片的Content-Type头
  3. 图片马

    • 在真实图片中嵌入恶意代码

4. 最佳实践建议

  1. 更严格的扩展名检查

    $allowed = ['jpg', 'jpeg', 'png'];
    if(!in_array(strtolower($uploaded_ext), $allowed))
    
  2. 重命名上传文件

    $new_name = md5(uniqid()).'.'.$uploaded_ext;
    
  3. 设置更严格的权限

    • 上传目录禁止执行PHP代码
  4. 二次渲染验证

    • 对图片进行重新渲染,去除可能的恶意代码
  5. 日志记录

    • 记录所有上传操作,便于审计

5. 完整代码示例

<?php
if( isset( $_POST[ 'Upload' ] ) ) {
    $target_path = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
    $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );
    
    $uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
    $uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1 );
    $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
    $uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];
    
    $allowed_exts = ['jpg', 'jpeg', 'png'];
    
    if( in_array(strtolower($uploaded_ext), $allowed_exts) 
        && ($uploaded_size < 100000) 
        && getimagesize($uploaded_tmp) ) {
        
        if( !move_uploaded_file( $uploaded_tmp, $target_path ) ) {
            echo '<pre>Your image was not uploaded.</pre>';
        } else {
            echo "<pre>{$target_path} successfully uploaded!</pre>";
        }
    } else {
        echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images under 100KB.</pre>';
    }
}
?>

6. 总结

DVWA的文件上传高级示例展示了相对安全的文件上传实现方式,包括:

  • 扩展名白名单验证
  • 文件大小限制
  • 文件内容验证
  • 安全的文件移动操作

然而,在实际应用中还需要考虑更多安全因素,如文件重命名、上传目录权限设置、日志记录等,才能构建真正安全的文件上传功能。

DVWA文件上传高级源码分析详解 1. 源码解析 1.1 基本结构 这段代码首先检查是否有名为'Upload'的POST请求提交,这是文件上传的触发条件。 1.2 文件路径设置 DVWA_WEB_PAGE_TO_ROOT 是一个常量,表示网站根目录的路径 basename() 函数提取文件名部分,防止路径遍历攻击 最终 $target_path 是完整的上传目标路径,如 /var/www/html/hackable/uploads/filename.ext 1.3 文件信息提取 strrpos() 找到文件名中最后一个 . 的位置 substr() 从 . 后一位开始截取,得到文件扩展名 1.4 文件验证逻辑 验证条件包括: 扩展名必须是jpg/jpeg/png(不区分大小写) 文件大小小于100KB(100000字节) getimagesize() 验证文件确实是有效的图片文件 1.5 文件移动处理 move_uploaded_file() 将临时文件移动到目标位置 该函数会自动检查文件是否是通过HTTP POST上传的合法文件 2. 关键函数详解 2.1 basename() 返回路径中的文件名部分 可以防止路径遍历攻击 示例: 2.2 strrpos() 返回字符串中最后一次出现的位置 用于查找文件名中最后一个 . 的位置 示例: 2.3 substr() 返回字符串的子串 用于提取文件扩展名 示例: 2.4 strtolower() 将字符串转换为小写 用于统一比较文件扩展名 示例: 2.5 getimagesize() 获取图像大小及相关信息 可以验证文件是否为真实图片 返回数组包含宽度、高度、类型等信息 2.6 move_ uploaded_ file() 将上传的文件移动到新位置 会自动检查文件是否是通过HTTP POST上传的合法文件 比普通的 rename() 更安全 3. 安全分析 3.1 防护措施 文件类型验证 : 检查扩展名(jpg/jpeg/png) 使用 getimagesize() 验证文件内容 文件大小限制 : 限制为100KB以内 路径安全 : 使用 basename() 防止路径遍历 3.2 潜在绕过方式 双扩展名攻击 : 如 shell.php.jpg 可能绕过扩展名检查 修改Content-Type : 伪造图片的Content-Type头 图片马 : 在真实图片中嵌入恶意代码 4. 最佳实践建议 更严格的扩展名检查 : 重命名上传文件 : 设置更严格的权限 : 上传目录禁止执行PHP代码 二次渲染验证 : 对图片进行重新渲染,去除可能的恶意代码 日志记录 : 记录所有上传操作,便于审计 5. 完整代码示例 6. 总结 DVWA的文件上传高级示例展示了相对安全的文件上传实现方式,包括: 扩展名白名单验证 文件大小限制 文件内容验证 安全的文件移动操作 然而,在实际应用中还需要考虑更多安全因素,如文件重命名、上传目录权限设置、日志记录等,才能构建真正安全的文件上传功能。