Improve MIME-type checks of uploaded files

This commit adds a check if the MIME-type of the uploaded file (detected using the magic bytes) matches the file extension.

Signed-off-by: David Mehren <git@herrmehren.de>
This commit is contained in:
David Mehren 2020-12-27 11:31:01 +01:00
parent f83e4d66ed
commit cf4344d9e0
No known key found for this signature in database
GPG key ID: 185982BA4C42B7C3
3 changed files with 302 additions and 49 deletions

View file

@ -2,6 +2,8 @@
const Router = require('express').Router
const formidable = require('formidable')
const path = require('path')
const FileType = require('file-type')
const config = require('../../config')
const logger = require('../../logger')
@ -9,6 +11,23 @@ const errors = require('../../errors')
const imageRouter = module.exports = Router()
async function checkUploadType (filePath) {
const typeFromMagic = await FileType.fromFile(filePath)
if (typeFromMagic === undefined) {
logger.error(`Image upload error: Could not determine MIME-type`)
return false
}
if (path.extname(filePath) !== '.' + typeFromMagic.ext) {
logger.error(`Image upload error: Provided file extension does not match MIME-type`)
return false
}
if (!config.allowedUploadMimeTypes.includes(typeFromMagic.mime)) {
logger.error(`Image upload error: MIME-type "${typeFromMagic.mime}" of uploaded file not allowed, only "${config.allowedUploadMimeTypes.join(', ')}" are allowed`)
return false
}
return true
}
// upload image
imageRouter.post('/uploadimage', function (req, res) {
var form = new formidable.IncomingForm()
@ -19,18 +38,17 @@ imageRouter.post('/uploadimage', function (req, res) {
form.uploadDir = config.uploadsPath
}
form.parse(req, function (err, fields, files) {
form.parse(req, async function (err, fields, files) {
if (err) {
logger.error(`Image upload error: formidable error: ${err}`)
return errors.errorForbidden(res)
} else if (!req.isAuthenticated() && !config.allowAnonymous && !config.allowAnonymousEdits) {
} else if (!req.isAuthenticated() && !config.allowAnonymous && !config.allowAnonymousEdits) {
logger.error(`Image upload error: Anonymous edits and therefore uploads are not allowed)`)
return errors.errorForbidden(res)
} else if (!files.image || !files.image.path) {
logger.error(`Image upload error: Upload didn't contain file)`)
return errors.errorBadRequest(res)
} else if (!config.allowedUploadMimeTypes.includes(files.image.type)) {
logger.error(`Image upload error: MIME-type "${files.image.type}" of uploaded file not allowed, only "${config.allowedUploadMimeTypes.join(', ')}" are allowed)`)
} else if (!await checkUploadType(files.image.path)) {
return errors.errorBadRequest(res)
} else {
logger.debug(`SERVER received uploadimage: ${JSON.stringify(files.image)}`)