Php file image upload security - php

$filename=$_FILES['file']['name'];
$type=$_FILES['file']['type'];
$extension=strtolower(substr($filename, strpos($filename, '.')+1));
$size=$_FILES['file']['size'];
if(($extension=='jpg' || $extension=='jpeg') && ($type!='image/jpg' || $type!='image/jpeg')){...
I have a input file, can let user upload jpg/jpeg image only, I have check type, extension, size.
However I'm not sure how to check if user change extension.(ex. abc.php -> abc.jpg)
any thing else I need to check before I save user's image into my server?

You can check the image with exif_imagetype()
http://www.php.net/manual/en/function.exif-imagetype.php
exif_imagetype() reads the first bytes of an image and checks its
signature.

I would suggest using finfo:
<?php
$finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
foreach (glob("*") as $filename) {
echo finfo_file($finfo, $filename) . "\n";
}
finfo_close($finfo);
/* outputs:
text/html
image/gif
application/vnd.ms-excel
*/
?>
example taken from php document site.
see more info on the php document page http://www.php.net/manual/en/function.finfo-file.php

#Fabian's answer looks good for checking the type of file. While I would suggest a different approach to getting the extension of the file.
Consider a file named stack.overflow.jpg.
$filename = 'stack.overflow.jpg';
// With your code $extension = 'overflow.jpg'
$extension=strtolower( substr( $filename, strpos( $filename, '.' ) +1 ) );
// With pathinfo() $extension = 'jpg'
$extension = pathinfo( $filename, PATHINFO_EXTENSION );
Consider using pathinfo() to get the file extension: http://www.php.net/manual/en/function.pathinfo.php

Related

How to dynamically determine unknown file extension from file in web folder [duplicate]

I want get uploaded image extension.
As I know, best way is getimagesize() function.
but this function's mime, returns image/jpeg when image has .jpg or also .JPEG extension.
How can get exactly extension?
$ext = pathinfo($filename, PATHINFO_EXTENSION);
you can use image_type_to_extension function with image type returned by getimagesize:
$info = getimagesize($path);
$extension = image_type_to_extension($info[2]);
You can also use strrpos and substr functions to get extension of any file
$filePath="images/ajax-loader.gif";
$type=substr($filePath,strrpos($filePath,'.')+1);
echo "file type=".$type;
output: gif
if you want extension like .gif
$type=substr($filePath,strrpos($filePath,'.')+0);
output: .gif
$image = explode(".","test.file.hhh.kkk.jpg");
echo end($image);
One more way to do it:
$ext = strrchr($filename, "."); // .jpg
$file_ext = pathinfo($_FILES["file"]["name"], PATHINFO_EXTENSION);
or to make it clean
$filename= $_FILES["file"]["name"];
$file_ext = pathinfo($filename,PATHINFO_EXTENSION);
You can also explode the file name with dots and take the end of the array as follows:
$ext = end(explode('.', 'image.name.gif'));
According to: Two different ways to find file extension in PHP
And a new way for you lol:
$ext = explode('.', 'file.name.lol.lolz.jpg');
echo $ext[count($ext) - 1];
For those who want to check if image type is JPEG, PNG or etc. You can use exif_imagetype function. This function reads the first bytes of an image and checks its signature. Here is a simple example from php.net:
<?php
if (exif_imagetype('image.gif') != IMAGETYPE_GIF) {
echo 'The picture is not a gif';
}
?>
$size = getimagesize($filename);
$ext = explode('/', $size['mime'])[1];

How Can I Secure This PHP Upload Script

I've read the Secure PHP Upload Scripts thread but I'm having difficulty getting this known good script to accept changes. I want this script to only allow .jpeg, .png, and .gif files. Could someone advise me on how to modify this script to do so?
<?php
$result=0;
if (trim($_POST["action"]) == "Upload File") { //**** User Clicked the Upload File Button
//*********** Execute the Following Code to Upload File *************
$imagename = basename($_FILES['image_file']['name']); // grab name of file
$result = #move_uploaded_file($_FILES['image_file']['tmp_name'], $imagename); // upload it
if ($result==1) echo("Successfully uploaded: <b>".$imagename."</b>"); // did it work?
} // end if
?>
<?php
if ($result==1) echo("<img src='".$imagename."'>"); // display the uploaded file
?>
$filename = $_FILES['image_file']['name'];
$ext = pathinfo($filename, PATHINFO_EXTENSION);
if($ext !== 'jpg' && $ext !== 'png' && $ext !== 'gif') {echo 'error';}
is a very bad idea for validation.
echo '<pre>';
$filename = 'image.php\0.jpg';
$extension = pathinfo($filename, PATHINFO_EXTENSION);
var_dump($ext);
The var_dump displays jpg
And the php function move_uploaded_file is vulnerable with null bytes \0.
After the move_uploaded_file the server will create a image.php file..
If you want to stop the upload before it reaches your server, you can filter it with javascript. See this SO answer for more information: stackoverflow.com/questions/71944/… – Kevin Apr 26 at 22:13
Never never never never neverever put trust in client side validation...
Coding a safe upload is hard. Very hard.
You can't trust file extensions or mime type because clients can change this.
If you only want an upload for gif, jpeg or png you could take these steps. With png you can have trouble because of the encoding that can bypass some of these.
Read the temp file by file_get_contents().
Run strip_tags() on it.
Create new images with the GD library
Serve the image by read() - Don't use include() or require()
Disable php engine on that directory
For the sake of brevity, i'm not doing any error checking.. but you can evaluate the extension of a file like this:
$filename = $_FILES['image_file']['name'];
$ext = pathinfo($filename, PATHINFO_EXTENSION);
if($ext !== 'jpg' && $ext !== 'png' && $ext !== 'gif') {echo 'error';}

Are still this code vulnerable to (Invalid File Uploading Attack) such as image that contains PHP code?

Providing user to upload images has wide usage, however, checking file extension and MIME type not guarantee correct file type.
Alternative:
I used imagejpeg() and imagecreatefromjpeg() functions for creating the image from $_FILE['userfile']['tmp_name'] and then saving it in images/ dir. In this case, I ignored move_uploaded_file() function.
Are still this code vulnerable to fake image uploading attack?
$filename = $_FILE['inputfile']['name'];
$upload_path = 'images/';
//extract extension
$ext = strtolower(substr($filename, strrpos($filename, '.') + 1));
// return mime type ala mimetype extension
$finfo = finfo_open(FILEINFO_MIME_TYPE);
//get MIME type of the given file
$mime = finfo_file($finfo, $filename);
//close finfo
finfo_close($finfo);
if (is_uploaded_file($_FILES['inputfile']['tmp_name'])) {
//first check: file extension and mime type
if(!in_array($ext, array('jpeg', 'jpg', 'gif', 'png')) && !in_array($mime, array('image/jpeg', 'image/gif', 'image/png')) ){
die("Error1: Invalid Image type");
}
if($ext == 'jpeg' || $ext == 'jpg'){
$im = #imagecreatefromjpeg($_FILE['inputfile']['tmp_name']);
if($im){
$createimage = imagejpeg($im, $upload_path.$_FILE['inputfile']['name']);
if(!$createimage){
die("Error3: Can't create image!");
}
//last check
$filecontent = file_get_contents($upload_path.$_FILE['inputfile']['name']);
//clean the file from any php code
$filecontent = str_replace(array("<?php", "<?", "?>"), "", $filecontent);
$handle = fopen($upload_path.$_FILE['inputfile']['name'], "wb");
fwrite($handle, $filecontent);
fclose($handle);
}
else{
die("Error2: Invalid Image Detected");
}
}
}
One can always embed PHP code safely in a perfectly valid image file. There are too many ways to do that to worth even thinking avoiding them. Many valid image formats, many data containers such as EXIF in jpg for example, pixel level and compression manipulation, etc.
To be on the safe side one should protect the server from arbitrary file inclusion attacks and sanitize the file extensions to escape from apache configuration mistakes.
A more crazy approach is to create a slightly modified copy of the image, more exactly create a new image from the original one modified, a slight resize or color manipulation will delete the bitmap level PHP injections while copying will save you from most of the PHP injected in other data containers within the image.

php upload not recoginsing .flv and f4v extensions

I have a page for uploading videos, and I want the file types to be mp4 flash and webm files. all the mp4 extension files and webm files work fine but the flash files (.flv and .f4v) are not recognized and therefore php returns the value 'application/octet-stream' which I believe is the default MIME for any files which aren't recognized. is there a better method than this code that will recognize the flash files for there true MIMES (video/x-flv and video/x-f4v) respectively?
$type = $_FILES["uploaded"]["type"];
$allowedTypes = ["video/mp4","video/quicktime","video/x-flv","video/x- f4v",
"video/webm"];
$isRefusedType = !in_array($type, $allowedTypes);
if ($isRefusedType)
{
$message="not an accepted file type";
}
else $message="OK";
Perhaps you can try this code:
<?php
$finfo = finfo_open(FILEINFO_MIME_TYPE); // mimetype
$type = finfo_file($finfo, $filename);
finfo_close($finfo);
?>
As described here, you will need PHP >= 5.3.0, is it a problem?
Another idea could be to check the data signature (see there):
<?php
$s = file_get_contents($_FILES["uploaded"]["tmp_name"]);
if ( substr($s,0,3) == 'FLV' ) { /* It's good! */ }
?>
Watching at the description of $_FILES['userfile']['type'] in the php documentation we can see:
The mime type of the file, if the browser provided this information.
An example would be "image/gif". This mime type is however not checked
on the PHP side and therefore don't take its value for granted.
So the Tiger-222 option seems to be your best chance to get the real value:
<?php
$finfo = finfo_open();
$fileinfo = finfo_file($finfo, $file, FILEINFO_MIME);
finfo_close($finfo);
?>

How to check uploaded file type in PHP

I used this code to check for the type of images,
$f_type=$_FILES['fupload']['type'];
if ($f_type== "image/gif" OR $f_type== "image/png" OR $f_type== "image/jpeg" OR $f_type== "image/JPEG" OR $f_type== "image/PNG" OR $f_type== "image/GIF")
{
$error=False;
}
else
{
$error=True;
}
but some users complain they get an error while uploading any type of images, while some others don't get any errors!
I was wondering if this fixes the problem:
if (mime_content_type($_FILES['fupload']['type']) == "image/gif"){...
Any comments?
Never use $_FILES..['type']. The information contained in it is not verified at all, it's a user-defined value. Test the type yourself. For images, exif_imagetype is usually a good choice:
$allowedTypes = array(IMAGETYPE_PNG, IMAGETYPE_JPEG, IMAGETYPE_GIF);
$detectedType = exif_imagetype($_FILES['fupload']['tmp_name']);
$error = !in_array($detectedType, $allowedTypes);
Alternatively, the finfo functions are great, if your server supports them.
In addition to #deceze, you may also finfo() to check the MIME-type of non-image-files:
$finfo = new finfo();
$fileMimeType = $finfo->file($path . $filename, FILEINFO_MIME_TYPE);
Sure you could check if it's an image with exif, but a better way I think is to do with finfo like this:
$allowed_types = array ( 'application/pdf', 'image/jpeg', 'image/png' );
$fileInfo = finfo_open(FILEINFO_MIME_TYPE);
$detected_type = finfo_file( $fileInfo, $_FILES['datei']['tmp_name'] );
if ( !in_array($detected_type, $allowed_types) ) {
die ( 'Please upload a pdf or an image ' );
}
finfo_close( $fileInfo );
The best way in my opinion is first to use getimagesize() followed by imagecreatefromstring().
$size = getimagesize($filename);
if ($size === false) {
throw new Exception("{$filename}: Invalid image.");
}
if ($size[0] > 2500 || $size[1] > 2500) {
throw new Exception("{$filename}: Image too large.");
}
if (!$img = #imagecreatefromstring(file_get_contents($filename))) {
throw new Exception("{$filename}: Invalid image content.");
}
Checking by getimagesize() prevents some DoS attacks, because we don't have to try to imagecreatefromstring() from every file provided by the user, either non-image file or file too big. Unfortunately, according to PHP docs cannot be relied on for checking image type content.
The imagecreatefromstring() finally tries to open the file as an image - if is succeeds - we have an image.
This is a simple, one line script that I use often.
$image = "/var/www/Core/temp/image.jpg";
$isImage = explode("/", mime_content_type())[0] == "image";
Basically I am using mime_content_type() to get something like "image/jpg" and then exploding it by "/" and checking against the first element of the array to see if it says "image".
I hope it works!
In PHP 5.5 I use this function for getting file type and check if image:
function getFileType( $file ) {
return image_type_to_mime_type( exif_imagetype( $file ) );
}
// Get file type
$file_type = getFileType( 'path/to/images/test.png' );
echo $file_type;
// Prints image/png
// 1. All images have mime type starting with "image"
// 2. No other non-image mime types contain string "image" in it
Then you could do:
if ( strpos( $filetype, 'image' ) !== false ) {
// This is an image
}
Complete list of mime types: http://www.sitepoint.com/web-foundations/mime-types-complete-list/
That last line is close. You can use:
if (mime_content_type($_FILES['fupload']['tmp_name']) == "image/gif"){...
In the case I'm currently working on, my $_FILES..['type'] reports itself as "text/csv", while both mime_content_type() and finfo() (suggested by others) report "text/plain.". As #deceze points out, $_FILES..['type'] is only useful to know what type a client thinks a file is.
you can try this
$file_extension = explode('.',$file['name']);
$file_extension = strtolower(end($file_extension));
$accepted_formate = array('jpeg','jpg','png');
if(in_array($file_extension,$accepted_formate)) {
echo "This is jpeg/jpg/png file";
} else {
echo $file_extension.' This is file not allowed !!';
}
WARNING: the following answer does not actually check the file type. It only checks the name. It is not suitable for actual security purposes.
EDIT: Don't Use this method as it serves no security check. I am leaving this answer here so that no one makes the same mistake like me by trying this.
I tried the following and it worked for me:
$allowed = array('gif','png' ,'jpg', 'pdf');
$filename = $_FILES['input_tag_name']['name'];
$ext = pathinfo($filename, PATHINFO_EXTENSION);
if(!in_array($ext,$allowed) ) {
echo 'error';
}
Source link

Categories