跳转至

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