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,});