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...
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:
http://www.php.net/manual/en/function.exif-imagetype.php
https://stackoverflow.com/a/11039258/3536236
PHP check if file is an image
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 ?
Related
If I put jpg header (1st line of a jpg file) in a HTML file and save it with jpg extension, then I can bypass the MIME type checking.
eg:
ÿØÿà JFIF d d ÿì Ducky < ÿî Adobe dÀ ÿÛ „
hyuhjjh
<script>
alert(hello);
</script>
If I save the above code as a JPG file then it can bypass the MIME type checking.
echo mime_content_type('x.html.jpg'); //shows 'image/jpeg'
I want the script to check the uploaded file content is purely of that content type( jpg/png or pdf or 3gp/mov). For image, document and video type.
OR doesn't contain any script.
Actually I need it for Drupal. So I have to use custom PHP code.
In Drupal 7.50 I have used "File Upload Secure Validator" to validate uploaded file MIME type, But it is useless for the above type of situation.
You need to use some library to actually load the file. For images I used GD to open the target image and check if it returns some reasonable height and width.
Same can be done with the other types. I guess that for video files this can be very resource-demanding, but it's the only way to be sure.
Right now I'm trying to write a script that will only accept certain audio files for upload to a server.
However, some MIME types are being returned as null.
Here is some code fragments:
PHP:
$allowedExt=array('audio/mp4a-latm');
if(isset($_POST))
{
print_r($_FILES);
//ToDo: Limit by File Size
if(in_array($_FILES["fileUpload"]["type"],$allowedExt)){
echo "file type found";
}
else
echo "wrong file type";
}
HTML:
<form action="php/FileUpload.php" method="POST" enctype="multipart/form-data">
Choose a file: <input name="fileUpload" type="file" /><br />
<input type="submit" value="Upload" />
</form>
The result of the above is:
Array ( [fileUpload] => Array ( [name] => 02 Helix Nebula.m4a [type] => [tmp_name] => <removed for space...>))
wrong file type
From what I understand, type should return the file's MIME type. In this case 'audio/mp4a-latm' for a .m4a file.
If php is properly returning null for .m4a files, then what would be the best approach to ensure I'm actually dealing with audio files? Is there anything more definite than just parsing for the file extensions? (ensure someone hasn't change the extension of say a text document)
The MIME element comes from the browser, which means it can be manipulated and thus is not trustworthy.
Either check the extension, or if you really want, parse the first few bytes of the file to make sure it's what is expected.
$_FILES['userfile']['type'] - The mime type of the file, if the browser provided this information.
http://www.php.net/manual/en/features.file-upload.post-method.php
That's why this method doesn't work well. You should compare file extension grabbed from
$_FILES['userfile']['name']
with acceptable extensions array (which you should create by yourself)
If you use php 5.3 or higher you can activate the php file info extension by escaping this line in your php.ini:
extension=php_fileinfo.dll
Then you can get your mime type from the file in php like this:
$pathToFile = 'my/path/to/file.ext';
$fileInfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($fileInfo, $pathToFile);
finfo_close($fileInfo);
This is more reliable than using what the browser sends you in the $_FILES array from your POST request.
In a site I'm developing I need to be able to pass all my images through imagejpeg(), so I decided (as my site only accepts JPG, BMP + PNG uploads) to simply convert BMPs and PNGs to a JPG first.
Now to convert the BMP I used the script found here:
http://forums.codewalkers.com/php-coding-7/how-to-convert-bmp-to-jpg-879135.html
The script works fine when I pass a normal BMP through it.
Now, I had a PNG which I had problems converting via imagecreatefrompng(), and after a while I realised it had the mime-type image/x-ms-bmp....
I tried passing the image through the BMP script but I get the following error:
Warning: imagecreatefromgd() [function.imagecreatefromgd]: 'C:\Users\Tom\AppData\Local\Temp\GD50C1.tmp' is not a valid GD file in C:\xampp\htdocs\test\cropimage\FCreateImageFromBMP.php on line 10
If anyone has come accross this before, please help.
If you need to see any code, just let me know.
Thanks in advance, Tom.
Edit:
Might be useful to mention, the line which the error occurs on (as from the link above) si this one:
$tmp_name = tempnam("/tmp", "GD");
The code you linked to bails out if a few preconditions fail:
if(!($src_f = fopen($src, "rb"))) {
...
if(!($dest_f = fopen($dest, "wb"))) {
...
if($type != 0x4D42) { // signature "BM"
So assuming that the source and tmp files are read/writable, it looks like the file you are giving it (which is sent as a .png but gives a BMP mime type) is in fact not a BMP file either, because the file contents don't start with the "BM" identifier. If you attach the file, perhaps somebody could identify what it really is.
Another solution I've used to this problem is to use ImageMagick's convert command to convert most file types, whatever they may be, to the desired format:
// convert uses the file extension to determine the output format, so
// change .jpg to whatever you'd like
$tmp_name = tempnam("/tmp", "convert") . '.jpg';
exec('c:\path\to\imagemagick\convert ' . $inputFile . ' ' . $tmp_name);
You can get ImageMagick for Windows and other platforms here:
Link
I have used the PHP method <form action="upload_file.php" method="post" enctype="multipart/form-data"> for uploading the excel sheets. Now I want to validate the excel sheet.
Validation:
If the sheet contain image instead of text I need to give an error to the user. Is it possible to validate the sheet's content without opening the sheet manually?
If you intend to use the data from the Excel file, you would have to parse and read it. If you can parse it as an Excel file, then its probably Excel, then you can safely rely on a php library like PHPExcel.
On the other hand, if you don't plan on using the data from the excel file, I personnally think that it would be overkill to use an entire library to validate if a file is in the right format.
$filename = $_POST['your_field_file'];
$finfo = finfo_open(FILEINFO_MIME_TYPE);
echo finfo_file($finfo, $filename);
or this
$filename = "/home/user1/whatever.xls"; //or $_POST['your_field_file'];
echo $finfo->file($filename);
It will return the MIME type, verify if it is excell file, then you can look the file size, and put some restrictions, but if you want to know what have inside the file, I think you need to open or parse the file. Try to use file_get_contents() and verify line by line if has an image there. (I'm not sure about that)
I hope this help.
Sounds like you should make use of the fileinfo PHP extension to check the mime types of the files users are uploading.
I am creating file upload script and I'm looking for the best techniques and practices to validate uploaded files.
Allowed extensions are:
$allowed_extensions = array('gif','jpg','png','swf','doc','docx','pdf','zip','rar','rtf','psd');
Here's the list of what I'm doing.
Checking file extension
$path_info = pathinfo($filename);
if( !in_array($path_info['extension'], $allowed_extensions) ) {
die('File #'.$i.': Incorrent file extension.');
}
Checking file mime type
$allowed_mimes = array('image/jpeg','image/png','image/gif','text/richtext','multipart/x-zip','application/x-shockwave-flash','application/msword','application/pdf','application/x-rar-compressed','image/vnd.adobe.photoshop');
if( !in_array(finfo_file($finfo, $file), $allowed_mimes) ) {
die('File #'.$i.': Incorrent mime type.');
}
Checking file size.
What should I do to make sure uploaded files are valid files? I noticed strange thing. I changed .jpg file extension to .zip and... it was uploaded. I thought it will have incorrect MIME type but after that I noticed I'm not checking for a specific type but if a specific MIME type exist in array. I'll fix it later, that presents no problems for me (of course if you got any good solution/idea, do not hesitate to share it, please).
I know what to do with images (try to resize, rotate, crop, etc.), but have no idea how to validate other extensions.
Now's time for my questions.
Do you know good techniques to validate such files? Maybe I should unpack archives for .zip/.rar files, but what about documents (doc, pdf)?
Will rotating, resizing work for .psd files?
Basically I thought that .psd file has following mime: application/octet-stream but when
I tried to upload .psd file it showed me (image/vnd.adobe.photoshop). I'm a bit confused about this. Do files always have the same MIME type?
Also, I cannot force code block to work. Does anyone have a guess as to why?
Lots of file formats have a pretty standard set of starting bytes to indicate the format. If you do a binary read for the first several bytes and test them against the start bytes of known formats it should be a fairly reliable way to confirm the file type matches the extension.
For example, JPEG's start bytes are 0xFF, 0xD8; so something like:
$fp = fopen("filename.jpg", "rb");
$startbytes = fread($fp, 8);
$chunked = str_split($startbytes,1);
if ($chunked[0] == 0xFF && $chunked[1] == 0xD8){
$exts[] = "jpg";
$exts[] = "jpeg";
}
then check against the exts.
could work.
If you want to validate images, a good thing to do is use getimagesize(), and see if it returns a valid set of sizes - or errors out if its an invalid image file. Or use a similar function for whatever files you are trying to support.
The key is that the file name means absolutely nothing. The file extensions (.jpg, etc), the mime types... are for humans.
The only way you can guarantee that a file is of the correct type is to open it and evaluate it byte by byte. That is, obviously, a pretty daunting task if you want to try to validate a large number of file types. At the simplest level, you'd look at the first few bytes of the file to ensure that they match what is expected of a file of that type.