Reputation: 528
I'm using NodeJS/Formidable and I try to secure my backend for the upload of images.
The classical way to check if the file is an image is to use a regexp like this :
if(!file.name || file.name.match(/\.(jpg|jpeg|png)$/i)) {
console.log("the file is an image");
}else{
console.log("the file is not an image");
}
and this :
var fileType = file.type.split('/').pop();
if(fileType == 'jpg' || fileType == 'png' || fileType == 'jpeg' ){
console.log("the file is an image");
} else {
console.log( 'incorrect file type: ' + fileType );
}
This a good check but this is not enough to be secure; in fact if I rename a PDF as a JPG for example, the browser provide a MIME/type : image/jpg based on the extension of the file. This is a security issue because you can rename a JS file or whatever to JPG and upload it in your backend filesystem.
I found this really interesting post : How to check file MIME type with javascript before upload?
It's perfect for the client side check but I'm not able to reproduce this in my backend.
I guess the ideal way is to analyse the stream on the fly and check the real MIME type after the upload of the first 4 bytes.
Any idea ?
Thx !
Upvotes: 3
Views: 1911
Reputation: 528
It works ! You can install a module like readChunk to transform the file into a buffer and write something like that :
form.on('file', function(field, file) {
buffer = readChunk.sync(file.path, 0, 4100);
filetype = fileType(buffer);
if(filetype.ext.match(/(jpg|jpeg|png)$/i)) {
fs.rename(file.path, path.join(form.uploadDir, file.name));
}else {
fs.unlink(file.path);
}
});
Upvotes: 2
Reputation: 17168
You should probably use something like the file-type npm package which takes a buffer (at least the first 4100 bytes) and will return you the MIME type and the file extension:
const fileType = require('file-type')
fileType(buffer) //=> {ext: 'png', mime: 'image/png'}
Upvotes: 2