JAVASCRIPT

Implement Secure Server-Side File Upload Validation

Learn to securely validate file uploads on the server-side, checking file type, size, and potential malicious content to prevent vulnerabilities and server abuse.

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

const app = express();
const uploadDir = path.join(__dirname, 'uploads');

// Ensure upload directory exists
if (!fs.existsSync(uploadDir)) {
  fs.mkdirSync(uploadDir);
}

// Multer storage configuration
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, uploadDir);
  },
  filename: (req, file, cb) => {
    // Generate a unique filename to prevent overwriting and path traversal
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
    cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname));
  }
});

// Multer upload middleware with validation
const upload = multer({
  storage: storage,
  limits: {
    fileSize: 5 * 1024 * 1024 // Max 5MB file size
  },
  fileFilter: (req, file, cb) => {
    const allowedMimeTypes = ['image/jpeg', 'image/png', 'application/pdf'];
    const allowedExtensions = ['.jpg', '.jpeg', '.png', '.pdf'];

    const fileExtension = path.extname(file.originalname).toLowerCase();
    
    // 1. Validate MIME type
    if (!allowedMimeTypes.includes(file.mimetype)) {
      return cb(new Error('Invalid file type. Only JPEG, PNG, and PDF are allowed.'));
    }

    // 2. Validate file extension
    if (!allowedExtensions.includes(fileExtension)) {
      return cb(new Error('Invalid file extension. Only .jpg, .jpeg, .png, and .pdf are allowed.'));
    }

    // 3. Optional: More advanced header/magic byte check for truly robust validation
    // This is often done by reading a few bytes of the file in the destination stream
    // and comparing them against known magic numbers for the expected file types.
    // For simplicity, it's omitted here but crucial for critical applications.

    cb(null, true); // Accept the file
  }
}).single('myFile'); // 'myFile' is the name of the input field in the form

// File upload route
app.post('/upload', (req, res) => {
  upload(req, res, (err) => {
    if (err instanceof multer.MulterError) {
      return res.status(400).send({ message: `Multer error: ${err.message}` });
    } else if (err) {
      return res.status(400).send({ message: `Upload error: ${err.message}` });
    }
    if (!req.file) {
      return res.status(400).send({ message: 'No file uploaded.' });
    }
    res.send({ message: 'File uploaded successfully!', filename: req.file.filename });
  });
});

app.get('/', (req, res) => {
    res.send(`
        <!DOCTYPE html>
        <html>
        <head><title>Upload</title></head>
        <body>
            <form action="/upload" method="post" enctype="multipart/form-data">
                Select file to upload:
                <input type="file" name="myFile" />
                <input type="submit" value="Upload File" />
            </form>
        </body>
        </html>
    `);
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});
How it works: This snippet demonstrates crucial server-side file upload validation using Express.js and `multer`. It prevents security risks by enforcing strict controls over uploaded content. Key validation steps include: 1) **Limiting file size** (`limits.fileSize`) to prevent denial-of-service attacks. 2) **Whitelisting MIME types** (`file.mimetype`) and **file extensions** (`path.extname`) to ensure only expected file types (e.g., images, PDFs) are accepted, preventing execution of malicious scripts. 3) **Generating unique filenames** (`multer.diskStorage.filename`) to prevent path traversal and overwriting existing files. While not shown in detail, for critical applications, verifying file "magic numbers" (actual file format bytes) is recommended for robust type validation beyond just MIME types and extensions.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs