Skip to main content

Insecure file upload

Need

Secure file upload and validation

Context

  • Usage of TypeScript for statically typed 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.single('file'), (req, res) => {
// Process the uploaded file
res.send('File uploaded successfully');
});

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

The vulnerability in this code is an insecure file upload. The code uses the Express framework and the Multer middleware to handle file uploads. However, it lacks proper validation and security checks, which can allow malicious files to be uploaded to the server.

The upload.single('file') middleware is used to handle a single file upload with the field name 'file'. However, it does not perform any validation on the file extension or content type.

This means that an attacker can easily bypass any restrictions on file types and upload files with unsafe extensions such as .html, .php, or .exe. These files can potentially contain malicious code that can harm the server or compromise the system.

To fix this vulnerability, the code should implement the following security measures:

  1. Validate the file extension: Use regular expressions or a whitelist approach to ensure that the uploaded file has a valid and safe extension. This can help prevent the upload of files with multiple extensions or unsafe extensions.

  2. Validate the file content: Use an antivirus software or a file scanning library to check the uploaded file for any malicious code or content. This can help detect and prevent the upload of files that may harm the server or compromise the system.

  3. Validate the Content-Type: Before uploading the file to the server, validate that the Content-Type header corresponds to the file's extension. This can help ensure that the file type matches its actual content and prevent any potential content spoofing attacks.

By implementing these security measures, the code can mitigate the risk of uploading and processing malicious files, making the file upload functionality more secure.

Steps

  • Install and import the 'mime-types' package.
  • Add a validation function to check if the file extension is safe.
  • Add a validation function to check if the file is free from malicious code.
  • Modify the upload middleware to include the file extension validation.
  • Modify the upload middleware to include the malicious code validation.
  • Modify the upload route handler to handle the validation errors and return appropriate responses.
  • Update the recommendation in the vulnerability description to include the new validations.

Compliant code

import express from 'express';
import multer from 'multer';
import { extname } from 'path';
import { lookup } from 'mime-types';

const app = express();
const upload = multer({
dest: 'uploads/',
fileFilter: (req, file, cb) => {
const safeExtensions = ['.jpg', '.png', '.gif']; // Add safe file extensions here
const fileExtension = extname(file.originalname).toLowerCase();
const isValidExtension = safeExtensions.includes(fileExtension);

if (!isValidExtension) {
return cb(new Error('Invalid file extension'));
}

const mimeType = lookup(fileExtension);
if (!mimeType || !mimeType.startsWith('image/')) {
return cb(new Error('Invalid file type'));
}

cb(null, true);
}
});

app.post('/upload', upload.single('file'), (req, res, next) => {
// Handle validation errors
if (req.fileValidationError) {
return res.status(400).json({ error: req.fileValidationError.message });
}

// Process the uploaded file
res.send('File uploaded successfully');
});

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

The fixed code addresses the vulnerability by implementing several validation checks before allowing file uploads.

  1. The code imports the necessary modules: express, multer, extname from the path module, and lookup from the mime-types module.

  2. It creates an instance of the express application and sets up the multer middleware for handling file uploads. The dest option specifies the destination directory for storing uploaded files.

  3. The code defines a fileFilter function that is passed to multer as an option. This function is responsible for validating the uploaded file. It checks if the file extension is in the list of safe extensions (e.g., .jpg, .png, .gif). If the extension is not valid, it returns an error.

  4. The fileFilter function also checks the file's MIME type using the lookup function from the mime-types module. It ensures that the MIME type starts with 'image/', indicating that the file is an image. If the MIME type is not valid, it returns an error.

  5. The fileFilter function calls the cb (callback) function with null as the first argument and true as the second argument if the file passes all the validation checks.

  6. The code sets up a route handler for the /upload endpoint using the app.post method. It uses the upload.single middleware to handle a single file upload with the field name 'file'.

  7. Inside the route handler, it checks if there are any validation errors (req.fileValidationError). If there are errors, it returns a JSON response with a 400 status code and the error message.

  8. If there are no validation errors, the code proceeds to process the uploaded file. In this example, it simply sends a success message as the response.

  9. Finally, the code starts the server and listens on port 3000.

The fixed code adds multiple layers of validation to ensure that only files with safe extensions and MIME types are allowed to be uploaded. This helps prevent the upload of malicious files to the server.

References