The Problem
Do you know a method in PHP to check the type of an uploaded file
without relying on extension or Mime-type because these two can be faked?
Verifying the file type in PHP
Relying on the Mime-type of a file submitted by a user is a bad practice, using the extension is even worse!
Some people use functions of the php fileinfo extension, these functions do not rely on file extensions but do rely on bytes sections of the file that can be easily faked.
You can retrieve the mime type with finfo_file() like this:
<?php $filename = "test.gif" $finfo = finfo_open(FILEINFO_MIME_TYPE); $file_mime_type = finfo_file($finfo, $filename); finfo_close($finfo); echo $file_mime_type; // Expected ouput: image/gif ?>
So you can use the php fileinfo functions to determine if the file is what it claims to be, I mean that the file extension matches the result of finfo_file(), if it doesn’t, there is no need to go further, the file should be rejected from being stored on your server and from beig served to your website visitors.
If the extension matches the MIME type we will have to go further and check if the files is really a GIF/JPEG/ZIP file or a fake file with malicious code.
For that we need to have a set of functions for the MIME types we are interested in, for images for example (TIFF, PNG, GIF, JPEG…), there is a good function that uses the identify linux command, modify it to suit your needs
<?php function is_jpg($fullpathtoimage){ exec("/usr/bin/identify -format %m $fullpathtoimage",$out); //using system() echos STDOUT automatically if(!empty($out)){ //identify returns an empty result if the file is not an image if($out === 'JPEG') return true; return false; } } ?>
Original code written by Ryan Day
Since I do not use file uploads, I can not provide functions for other file types, but I will search for them and edit my post if I find any.
There’s another solution that should work for all types but I’m not sure about it, it uses the linux file command:
<?php
function file_mime_type($fullpathtoimage){
exec("/usr/bin/file -bi $fullpathtoimage",$out);
$mime_type = array_shift(explode(';',$out[0]));
return $mime_type;
}
// Test
print_r(file_mime_type(__FILE__)); // Outputs: text/x-c++ which is ok
?>
I prefer the ‘file’ unix command because it relies on the header or signature of the file.
I think a good soluion for security would be to nest several tests both client side and server side, beginning from the simple check of the file extension, and going through some test like the one you exposed for checking the actual type of the file, and ending with a server side antivirus testing if the type of the file has been accepted. I’m not a good php programmer but I think combining php functions and some other server scripting can lead to an acceptable solution.
Thank you for the answer!
Yes, using server software (specially antiviruses) will bring higher levels of security, but this is only available on dedicated servers.
using exec and not even escaping/validating/sanitizing inputs is just as bad – if not even worse, as users have now direct shell access.
I agree that using fileinfo extension (or any other pseudo type check like file/identify/whatever) should _only_ be used as pre-check. If you decide to host the uploaded file, always do an analog copy of the pixels. With this you are sure only to get the picture information and not any other files attached.