Unrestricted file upload
无限制的文件上传
描述
无限制的文件上传(Unrestricted File Upload)对应用程序构成重大风险,可能导致系统接管、文件系统过载、客户端攻击或网页篡改(defacement)。此漏洞可能是由于不安全的文件元数据验证(例如 HTTP Multi-part 字段)或不安全的内容和大小验证(例如上传未经授权的文件格式)造成的。
建议
为了缓解与无限制文件上传相关的风险,请考虑以下措施:
- Validate File Type: 实施服务器端验证,以确保仅允许上传经过授权的文件类型。将允许的文件扩展名列入白名单,并拒绝任何具有不允许扩展名的文件。避免单独使用客户端验证,因为它很容易被绕过。
- Check File Content: 验证上传文件的内容,以确保其与声明的文件类型匹配。例如,对于图像上传,使用库或工具检查文件头,以确认它们确实是图像。
- Rename Uploaded Files: 重命名上传的文件,以防止攻击者通过猜测文件名来执行它们。结合使用随机字符串和服务器生成的唯一标识符,为上传的文件创建新文件名。
- Store Uploaded Files in a Secure Location: 将上传的文件存储在 Web 根目录之外,以防止通过 URL 直接访问。例如,您可以使用 S3 存储桶(S3 buckets)。
- Scan Uploaded Files for Malware: 利用防病毒或反恶意软件扫描程序来扫描上传文件中的恶意内容。实施定期扫描,以确保服务器上不存在恶意文件。
- Monitor File Upload Activities: 实施日志记录和监控机制以跟踪文件上传活动。监控任何可疑或异常的文件上传模式,并在检测到后立即采取行动。
const express = require('express');
const multer = require('multer');
const path = require('path');
const { v4: uuidv4 } = require('uuid');
const app = express();
// Define storage for uploaded files
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, 'uploads/');
},
filename: function (req, file, cb) {
const ext = path.extname(file.originalname);
cb(null, uuidv4() + ext);
}
});
// File filter to allow only specified file extensions
const fileFilter = (req, file, cb) => {
const allowedExtensions = ['.jpg', '.jpeg', '.png'];
const ext = path.extname(file.originalname).toLowerCase();
if (allowedExtensions.includes(ext)) {
cb(null, true);
} else {
cb(new Error('File type not allowed!'), false);
}
};
// Initialize multer with storage and file filter
const upload = multer({ storage: storage, fileFilter: fileFilter });
// POST endpoint for file upload
app.post('/upload', upload.single('file'), (req, res) => {
res.send('File uploaded successfully!');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
from django.conf import settings
from django.core.files.storage import FileSystemStorage
from django.http import HttpResponseBadRequest
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
import os
from uuid import uuid4
@require_POST
def upload_file(request):
if request.method == 'POST' and request.FILES['file']:
file = request.FILES['file']
allowed_extensions = ['.jpg', '.jpeg', '.png']
ext = os.path.splitext(file.name)[1]
if ext.lower() not in allowed_extensions:
return HttpResponseBadRequest('File type not allowed!')
fs = FileSystemStorage()
filename = fs.save(str(uuid4()) + ext, file)
return HttpResponse('File uploaded successfully!')
else:
return HttpResponseBadRequest('No file found!')
<?php
$uploadDir = 'uploads/';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
$file = $_FILES['file'];
$allowedExtensions = array('.jpg', '.jpeg', '.png');
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($ext, $allowedExtensions)) {
http_response_code(400);
echo 'File type not allowed!';
exit;
}
$uploadFile = $uploadDir . uniqid() . '.' . $ext;
if (move_uploaded_file($file['tmp_name'], $uploadFile)) {
echo 'File uploaded successfully!';
} else {
http_response_code(500);
echo 'Error uploading file.';
}
} else {
http_response_code(400);
echo 'No file found!';
}
?>
链接
标准
- CWE_TOP_25:
- CWE_434
- PCI_STANDARDS:
- REQ_2_2
- REQ_6_2
- REQ_6_3
- REQ_6_4
- REQ_11_3
- SOC2_CONTROLS:
- CC_2_1
- CC_3_4
- CC_4_1
- CC_6_1
- CC_7_1
- CC_7_2
- CC_7_4
- CC_7_5
- HIPAA_CONTROLS:
- SECURITY221
- SECURITY212
- SECURITY213