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 ) ) {
// 验证通过后的处理
}
验证条件包括:
- 扩展名必须是jpg/jpeg/png(不区分大小写)
- 文件大小小于100KB(100000字节)
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 防护措施
-
文件类型验证:
- 检查扩展名(jpg/jpeg/png)
- 使用
getimagesize()验证文件内容
-
文件大小限制:
- 限制为100KB以内
-
路径安全:
- 使用
basename()防止路径遍历
- 使用
3.2 潜在绕过方式
-
双扩展名攻击:
- 如
shell.php.jpg可能绕过扩展名检查
- 如
-
修改Content-Type:
- 伪造图片的Content-Type头
-
图片马:
- 在真实图片中嵌入恶意代码
4. 最佳实践建议
-
更严格的扩展名检查:
$allowed = ['jpg', 'jpeg', 'png']; if(!in_array(strtolower($uploaded_ext), $allowed)) -
重命名上传文件:
$new_name = md5(uniqid()).'.'.$uploaded_ext; -
设置更严格的权限:
- 上传目录禁止执行PHP代码
-
二次渲染验证:
- 对图片进行重新渲染,去除可能的恶意代码
-
日志记录:
- 记录所有上传操作,便于审计
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的文件上传高级示例展示了相对安全的文件上传实现方式,包括:
- 扩展名白名单验证
- 文件大小限制
- 文件内容验证
- 安全的文件移动操作
然而,在实际应用中还需要考虑更多安全因素,如文件重命名、上传目录权限设置、日志记录等,才能构建真正安全的文件上传功能。