Cách Tạo Hệ Thống Upload File An Toàn Với Node.js và Multer

17/03/2026 P T P Chung 8 phút đọc 0 bình luận

Mở đầu

Trong các ứng dụng web hiện đại, khả năng cho phép người dùng upload file là một tính năng phổ biến. Tuy nhiên, nếu không được xử lý đúng cách, nó có thể trở thành lỗ hổng bảo mật nghiêm trọng. Bài viết này sẽ hướng dẫn cách xây dựng một hệ thống upload file an toàn bằng Node.js và thư viện Multer, đồng thời đề cập đến các thực hành bảo mật quan trọng.

Vì sao cần quan tâm đến bảo mật khi upload file?

File upload là một trong những cửa ngõ dễ bị khai thác nhất. Kẻ tấn công có thể upload file chứa mã độc, script ẩn, hoặc file giả mạo định dạng nhằm chiếm quyền kiểm soát server. Nếu không kiểm tra kỹ lưỡng, hệ thống có thể bị xâm nhập, dữ liệu bị đánh cắp, hoặc server bị treo do upload file quá lớn. Do đó, việc thiết kế hệ thống upload an toàn là điều bắt buộc, không phải là tùy chọn.

Multer là gì và tại sao nên dùng nó?

Multer là middleware phổ biến nhất cho Node.js, được thiết kế riêng để xử lý multipart/form-data - định dạng dữ liệu thường dùng khi upload file. Multer giúp dễ dàng lưu file vào disk hoặc memory, đồng thời cung cấp các tùy chỉnh về giới hạn kích thước, filter file type, và đặt tên file. Tuy nhiên, Multer chỉ xử lý việc lưu file, còn việc kiểm tra bảo mật phải do developer tự thực hiện.

Các bước xây dựng hệ thống upload an toàn

1. Thiết lập dự án và cài đặt dependencies

Trước tiên, khởi tạo một project Node.js và cài đặt các thư viện cần thiết:

npm init -y
npm install express multer fs-extra

2. Cấu hình Multer với các tùy chọn bảo mật

Tạo thư mục uploads để lưu file và cấu hình Multer:

const express = require('express');
const multer = require('multer');
const path = require('path');
const fs = require('fs');

const app = express();

// Tạo thư mục uploads nếu chưa có const uploadDir = 'uploads'; if (!fs.existsSync(uploadDir)) { fs.mkdirSync(uploadDir); }

// Cấu hình Multer const storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, uploadDir); }, filename: (req, file, cb) => { // Đặt tên file an toàn, tránh overwrite const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9); cb(null, uniqueSuffix + path.extname(file.originalname)); } });

// Filter file type function fileFilter(req, file, cb) { const allowedTypes = /jpeg|jpg|png|gif|pdf/; const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase()); const mimetype = allowedTypes.test(file.mimetype); if (extname && mimetype) { return cb(null, true); } else { cb(new Error('Chỉ cho phép upload file ảnh và PDF')); } }

// Giới hạn kích thước file const limits = { fileSize: 1024 1024 5 // 5MB };

const upload = multer({ storage: storage, fileFilter: fileFilter, limits: limits });

Quảng cáo

300x250 In-Content Advertisement

3. Tạo route upload và xử lý lỗi

app.post('/upload', upload.single('file'), (req, res) => {
  if (!req.file) {
    return res.status(400).json({ error: 'Không tìm thấy file' });
  }
  res.json({
    message: 'Upload thành công',
    file: {
      originalname: req.file.originalname,
      filename: req.file.filename,
      size: req.file.size,
      mimetype: req.file.mimetype
    }
  });
});

// Xử lý lỗi Multer app.use((err, req, res, next) => { if (err instanceof multer.MulterError) { return res.status(400).json({ error: 'Lỗi upload file' }); } if (err) { return res.status(400).json({ error: err.message }); } next(); });

4. Kiểm tra file type và nội dung

Không nên chỉ dựa vào phần mở rộng file. Sử dụng package file-type để kiểm tra magic number (dữ liệu nhận dạng định dạng file):

npm install file-type
const fileType = require('file-type');

async function checkFileType(file) { const buffer = await file.stream.slice(0, 4100).buffer(); const type = await fileType.fromBuffer(buffer); const allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf']; return allowedTypes.includes(type?.mime); }

5. Đặt file ngoài thư mục public và đổi tên file

Lưu file trong thư mục không thể truy cập trực tiếp qua URL. Nếu cần phục vụ file, tạo route riêng và kiểm tra quyền truy cập:

app.get('/files/:filename', (req, res) => {
  const filePath = path.join(uploadDir, req.params.filename);
  if (fs.existsSync(filePath)) {
    res.sendFile(filePath);
  } else {
    res.status(404).json({ error: 'File không tồn tại' });
  }
});

6. Giới hạn số lượng file và kích thước upload

Với multiple upload:

upload.array('files', 5) // tối đa 5 file

Hoặc dùng upload.fields() cho form phức tạp.

Các thực hành bảo mật bổ sung

- Quét virus: Tích hợp công cụ quét virus như ClamAV. - Dọn dẹp định kỳ: Xóa file cũ hoặc không sử dụng. - Ghi log: Lưu lại mọi hoạt động upload để audit. - Dùng HTTPS: Mã hóa dữ liệu truyền tải. - Validate trên client: Giúp trải nghiệm tốt hơn, nhưng không thay thế validate server.

Kết luận

Xây dựng hệ thống upload file an toàn không chỉ đơn thuần là lưu file vào server. Nó đòi hỏi sự cẩn trọng trong từng bước: kiểm soát định dạng, giới hạn kích thước, đặt tên file an toàn, lưu trữ ở vị trí thích hợp, và luôn validate cả client lẫn server. Multer là công cụ mạnh mẽ, nhưng developer phải chủ động bổ sung các lớp bảo mật. Với những thực hành này, bạn có thể tự tin cung cấp tính năng upload file mà vẫn bảo vệ hệ thống trước các mối đe dọa.

Quảng cáo

728x90 Bottom Advertisement

Thay thế bằng mã Google AdSense

Chia sẻ bài viết

Facebook Twitter

Bình luận

Chia sẻ ý kiến của bạn về bài viết này

Viết bình luận

Bình luận của bạn sẽ được kiểm duyệt trước khi hiển thị

Chưa có bình luận nào

Hãy là người đầu tiên bình luận về bài viết này!