Insecure file upload - Files Limit - TypeScript

Insecure file upload - Files Limit - TypeScript

Need

Enforce file upload limits and implement proper file management

Context

  • Usage of TypeScript for type-checking and static typing in JavaScript development
  • Usage of Express for building web applications and APIs
  • Usage of multer for handling file uploads in Node.js

Description

Non compliant code

        import express from 'express';
import multer from 'multer';

const app = express();
const upload = multer({ dest: 'uploads/' });

app.post('/upload', upload.array('files'), (req, res) => {
  res.status(200).json({ message: 'Files uploaded successfully' });
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});
        
        

The vulnerability in this code is an insecure file upload due to the lack of a limit on the number of files that can be uploaded to the system per unit of time. Additionally, uploading a new file does not delete the previous file from the server.

The code uses the Express framework and the Multer middleware for handling file uploads. It sets up a route at /upload that accepts file uploads using the upload.array('files') middleware. The uploaded files are stored in the uploads/ directory.

The issue with this code is that there is no mechanism in place to limit the number of files that can be uploaded. An attacker can exploit this by repeatedly uploading large numbers of files, potentially exceeding the server's storage capacity and causing resource exhaustion.

Furthermore, the code does not delete the previous files when a new file is uploaded. This can lead to unnecessary accumulation of files on the server, consuming storage resources indefinitely.

To mitigate this vulnerability, it is recommended to implement the following measures:

1. Set a limit on the number of files that can be uploaded within a specific time period. This can be achieved by implementing throttling or rate limiting mechanisms.

2. Delete the previous files when a new file is uploaded. This can be done by adding code to delete the existing files before saving the new ones.

By implementing these recommendations, the code can prevent excessive resource consumption and ensure that the server's storage is not unnecessarily occupied by unused files.

Steps

  • Set a limit to the number of files that can be uploaded per unit of time.
  • Delete previous avatar files when uploading a new one.
  • Apply throttling to limit the rate of file uploads.
  • Update the code to handle the file upload limit and delete previous files.
  • Test the updated code to ensure it is working correctly.

Compliant code

        import express from 'express';
import multer from 'multer';
import fs from 'fs';

const app = express();
const upload = multer({ 
  dest: 'uploads/',
  limits: { 
    files: 1, // Set the limit to 1 file per upload
    fileSize: 1024 * 1024 // Set the maximum file size to 1MB
  }
});

app.post('/upload', upload.array('files'), (req, res) => {
  // Delete previous avatar files
  fs.readdir('uploads/', (err, files) => {
    if (err) throw err;
    for (const file of files) {
      fs.unlink(`uploads/${file}`, (err) => {
        if (err) throw err;
      });
    }
  });

  res.status(200).json({ message: 'Files uploaded successfully' });
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});
        
        

The fixed code addresses the vulnerability by implementing several measures.

1. The code uses the multer library to handle file uploads. It sets the destination folder for uploaded files to the 'uploads/' directory.

2. The upload middleware is configured with limits to restrict the number of files that can be uploaded and the maximum file size. The 'files' limit is set to 1, ensuring that only one file can be uploaded per request. The 'fileSize' limit is set to 1MB, preventing excessively large files from being uploaded.

3. The '/upload' route handles the file upload request. It uses the upload.array() function to process the uploaded files. This function expects the name of the file input field, which is 'files' in this case.

4. Before saving the new file, the code deletes any previously uploaded avatar files from the 'uploads/' directory. It uses the fs.readdir() function to read the contents of the directory and fs.unlink() to delete each file. This ensures that only the latest avatar file is stored on the server, preventing storage resource exhaustion.

5. Finally, the code sends a JSON response with a success message indicating that the files were uploaded successfully.

By implementing these measures, the code limits the number of files that can be uploaded, restricts the file size, and deletes previous avatar files, effectively mitigating the insecure file upload vulnerability.

References