2

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 !

Community
  • 1
  • 1
Cyril Blanchet
  • 432
  • 5
  • 8

2 Answers2

1

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'} 
idbehold
  • 15,541
  • 3
  • 40
  • 65
1

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

});
Cyril Blanchet
  • 432
  • 5
  • 8