What is the safest way to identify that the upload file is an image?

7

I'm making a system where I can receive an image upload.

To check on the server if the file type is image, I thought of this code:

if (strpos($upload->getClientMimeType(), 'image') !== 0) {

    throw new UploadException(
        sprintf('Extensão de arquivo %s é inválida', $upload->getClientOriginalExtension())
    );
}

That is, checking if the mime of the file starts with "image" , to know if it is an image or not, since image memos are usually image/png , image/jpeg , image/gif ...

But I was wondering if this really would be safe, as well as having your own concern if there is no other image-type file that does not have the mime prefixed by image .

I would like to know:

  • Is the example shown for image verification sufficient to maintain upload security or not?

What are the best ways to check image uploads in PHP?

Note : I'm currently using the framework , but I would not mind receiving good suggestions using pure pure php .

    
asked by anonymous 20.01.2017 / 13:30

2 answers

6

As I see it technically has no problem using mimetypes, it's actually much more secure with them than file extensions (which many people unfortunately do), something I explained Here's how to do it with PHP

The only problem I see is the lack of / after image in:

if (strpos($upload->getClientMimeType(), 'image') !== 0) {

What would allow a document to have a mimetype like this imagexyz/foobar , this is not a security hole, since I do not really know if it can cause something, since I do not think there are other mimetypes that start with image***/ , for guarantee do:

if (strpos($upload->getClientMimeType(), 'image/') !== 0) {

Of course this will allow you to upload:

  • icons ( image/icon , image/x-icon , image/vnd.microsoft.icon )
  • svg ( image/svg+xml )
  • Photoshop (% with%)

Among others.

This is your choice, so if you want to limit to jpg, gif and png formats use in_array:

$formatospermitidos = array( 'image/jpeg', 'image/gif', 'image/png' );

if (!in_array($upload->getClientMimeType(), $formatospermitidos)) {
    
20.01.2017 / 13:44
6

As the best options have already been mentioned by the @Guilherme Nascimento , I add an addition to his answer:

In PHP there is the function exif_imagetype in which it determines the type of image through the signature in the first% of the file%, analyzing in a deeper way, based on predefined constants, being they:

Value   Constant
1   IMAGETYPE_GIF
2   IMAGETYPE_JPEG
3   IMAGETYPE_PNG
4   IMAGETYPE_SWF
5   IMAGETYPE_PSD
6   IMAGETYPE_BMP
7   IMAGETYPE_TIFF_II (intel byte order)
8   IMAGETYPE_TIFF_MM (motorola byte order)
9   IMAGETYPE_JPC
10  IMAGETYPE_JP2
11  IMAGETYPE_JPX
12  IMAGETYPE_JB2
13  IMAGETYPE_SWC
14  IMAGETYPE_IFF
15  IMAGETYPE_WBMP
16  IMAGETYPE_XBM
17  IMAGETYPE_ICO

An example of its use:

if (exif_imagetype('image.gif') != IMAGETYPE_GIF) {
    echo 'O arquivo não é .gif';
}

PS¹: As Guilherme reminded you, bytes functions are usually not enabled by default.

PS2: Depending on how these images being loaded will be handled, I advise you to explicitly tell which types are supported so that you are not dealing with a simple exif_* image and receive .gif , for example.

    
20.01.2017 / 14:03