0

I try to write a upload form and I want user to sent only image or pdf file. To detect mime type I use finfo but it's really easy to mess with him here an example

<?php

$cnt ='<form action="" method="get">\x0aCommand: <input type="text" name="cmd" /><input type="submit" value="Exec" />\x0a</form>\x0aOutput:<br />\x0a<pre><?php passthru($_REQUEST["cmd"], $result); ?></pre>\x0a';
echo $cnt."\n";
$finfo = new \finfo(FILEINFO_MIME);
echo $finfo->buffer($cnt) . "\n"; // text/plain; charset=us-ascii

$cnt ="\xff\xd8\xff\xe0\x0a".$cnt; // adding random utf8 char at the begining
echo $cnt."\n";
$finfo = new \finfo(FILEINFO_MIME);
echo $finfo->buffer($cnt) . "\n";  // image/jpeg; charset=iso-8859-1

Does any body know how to do it properly ?

Update:

Ok so let's reveal the magic trick : finfo like many or tool ( cmd file on unix for example) use a "magic table" to find out which kind of file is it. Look at those example

Short version finfo search for a series of specific bytes in the stream and if it found it, it return the mime type associated with those number.

To trick it, you just have to had those bytes in your file...

Which does not answer the question on how to find out properly...

  • What have you tried? What went wrong? https://stackoverflow.com/help/how-to-ask – Hans Dash Mar 13 '21 at 16:45
  • There are a few methods to improve file security, the most effective for images is to convert the image in PHP into a PNG or other format, and then reload it and convert it back tothe desired format. If the original image code is malformed (as you example) it will not successfully convert. This will be detected by PHP (as `false`) . This can't apply to PDF but can ensure images are genuine and also can remove potentially dangerous metadata from JPG images by converting them as PNG and then back to JPG again – Martin Mar 13 '21 at 17:47
  • Hey that what I though... For pdf I guess I can open the file and try to get the page number.. If it failed thats mean its not a pdf... but this seems quite complicated... – Chonkchonk Mar 13 '21 at 18:12
  • @HansDash I tried to get the mime type using finfo but for a php file it told me that was a jpeg file. – Chonkchonk Mar 13 '21 at 18:14
  • @Chonkchonk [this post](https://stackoverflow.com/a/11039258/3536236) might also be useful to you re PDF – Martin Mar 13 '21 at 18:16
  • Seeing the argument of finfo constructor https://www.php.net/manual/fr/function.finfo-open.php I guess it already work that way – Chonkchonk Mar 13 '21 at 18:34

2 Answers2

0

Here is how you can Get the File extension of an image :

$path = $_FILES['image']['name'];
$ext = pathinfo($path, PATHINFO_EXTENSION);

Here is the Html code :

<form action="" method="POST">
        <input type="file" name="" id="" accept="application/pdf,image/jpeg">
<input type="submit" name="submit" value="">
</form>

Why are you using Finfo ?

Ryan The Ghost
  • 116
  • 1
  • 13
0

There are a few methods to improve file security;

The most effective for images is to convert the image in PHP into another format such as from JPEG to PNG, and then reload it (in PHP memory) and convert it back to the desired format.

If the original image code is malformed (as you example) it will not successfully convert; this will be detected by PHP (as false or similar).

There are additional parallel test you can do such as using getimagesize to check the values returned correlate with expected values from the original file and from the converted file etc.

If an image, a vague process could be:

  • Check file finfo MIME type (as you already do)
  • Convert file to another format (ie JPG --> PNG ).
  • Test file dimensions (getimagesize). Remember these.
  • Convert file data in PHP Memory back to original format (ie PNG --> JPG).
  • Test if these file dimensions (getimagesize) compare with values from above.

This can't apply to PDF but can ensure images are genuine and also can remove potentially dangerous metadata from JPG images by converting them to PNG and then back to JPG again.

This post might also be useful to you re PDF

Essentially, files are only going to be blocks of data and to this extent MIME type checks (in isolation) will never be a surefire way of promising the file is "genuine". MIME type is like the cover of a book; the cover looks like a literary masterpiece, but until you flick through the pages and find it's all 1980s pornography you won't be sure.

Some useful links:

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Martin
  • 22,212
  • 11
  • 70
  • 132
  • for pdf we can try ton convert it to a series of image : https://pdf.wondershare.com/pdf-knowledge/php-pdf-to-image.html but this will not remove potentially dangerous data form it – Chonkchonk Mar 13 '21 at 20:23
  • For image file, converting a jpg to anything else (event jpg) will cause a loose of quality : this should not be a problem but it's important to know read that for more info : https://cloudinary.com/blog/why_jpeg_is_like_a_photocopier – Chonkchonk Mar 13 '21 at 20:25
  • @Chonkchonk no that is incorrect; a jPEG has a quality factor (0-100) and this effects file size; but quality above 75 is indistinguishable to the human eye. Also the PHP processes the quality of the transitions is fully user controllable so wouldn't be an issue. Likewise converting a 90 quality PJEG to a 9 PNG, will result in no image quality loss but will result in a file size increase. – Martin Mar 13 '21 at 21:03
  • @Chonkchonk the link you reference in your comment is full of assumptions and is not correct. A duplicate of a 90 quality JPEG is going to be a 90 quality JPEG, because the duplicate is a *file* duplicate not an *image* duplicate. – Martin Mar 13 '21 at 21:04