Skip to content

Weak Multer File Name Manipulation

The multer library allows developers to put in place a custom fileFilter callback function that multer will call as part of the file upload processing in order to customize the logic of which file types are allowed and disallowed.

Following is an example of such insecure file type validation:

import multer from 'multer';
const fileFilter = (req, file, cb) => {
if (file.mimetype === 'image/png' || file.mimetype === 'image/jpeg') {
cb(null, true);
} else {
cb(new Error('Invalid file type, only PNG and JPEG is allowed!'), false);
}
};
const upload = multer({
dest: 'uploads',
fileFilter,
});

The reason I refer to this practice as insecure is because the req.mimetype validation here is not a reliable source of truth and can be easily manipulated by an attacker. The mimetype property is derived from the Content-Type header of the request, which can be changed by the adversarial that sends the HTTP request to the server.

Weak File Type and File Name Handling in Multer

The following is an example of both weak and insecure fileType and fileName handling in a multer configuration:

const uploadFolder = './static_temp';
const urlPath = './static/files';
console.log(uploadFolder);
createFolder(uploadFolder);
const storage = multer.diskStorage({
destination: function (req, file, cb) {
// 接收到文件后输出的保存路径(若不存在则需要创建)
cb(null, uploadFolder);
},
filename: function (req, file, cb) {
// 将保存文件名设置为 时间戳 + 文件原始名,比如 151342376785-123.jpg
cb(null, Date.now() + "-" + file.originalname);
}
});
const storageAvatar = multer.diskStorage({
destination: function (req, file, cb) {
// 接收到文件后输出的保存路径(若不存在则需要创建)
cb(null, uploadFolder);
},
filename: function (req, file, cb) {
// 将保存文件名设置为 时间戳 + 文件原始名,比如 151342376785-123.jpg
cb(null, ~~(Math.random() * 999999) + "avatar-" + file.originalname);
}
});
const fileFilter = (req, file, cb) => {
const fileType = file.mimetype.toLowerCase();
if(fileType === 'image/png' || fileType === 'image/jpg' || fileType === 'image/jpeg' || fileType === 'image/webp') {
cb(null, true)
} else {
cb(null, false)
}
}
// 创建 multer 对象
const upload = multer({
storage: storage,
limits: {
fields: 10,
files: 10,
fileSize: 5 * 1024 * 1024
},
fileFilter,
});