How to restrict file upload using PHP? - php

I am trying to do a restricted file upload using PHP.
I have used
if (($_FILES["file"]["type"] == "application/dbase")
||($_FILES["file"]["type"] == "application/dbf")
||($_FILES["file"]["type"] == "application/x-dbase")
||($_FILES["file"]["type"] == "application/x-dbf")
||($_FILES["file"]["type"] == "zz-application/zz-winassoc-dbf"))
For me .dbf (i.e Microsoft Visual FoxPro Table type) files are not working. Please suggest to me what I should put for the content type for .dbf .

The browser uploading the file probably doesn't know it's an application/dbf mime-time, and sends it as the generic "application/octet-stream". The client/browser has to set the mime-type to be known on upload, and this can be altered by the user!
Thus MIME-type isn't reliable. If you want to be sure that it's the correct file-type/format, you'll have to examine the uploaded file.

There is another easy way for this problem , instead of inspecting the MIME type,
we can get the file extension of the uploaded file by using this function.
$filename=$_FILES["file"]["tmp_name"];
$ext = pathinfo($filename, PATHINFO_EXTENSION);
$ext = strtolower($ext);
if($ext=="png"||$ext=="gif"||$ext=="jpg"||$ext=="jpeg"||$ext=="pdf"
||$ext=="doc"||$ext=="docx"||$ext=="xls"
||$ext=="xlsx"||$ext=="xlsm"||$ext=="dbf")
{
// your code whatever you want to write;
}
Find an easy blob-upload and download of file here Blob-upload

Defining the content type is up to the browser (or other client application), making it easy to tamper with and cannot be relied upon. My guess is that your browser doesn't recognize the .dbf file and defaults to "application/octet-stream".

You can't depend on the type field of a file upload to actually determine its type. First, it can be spoofed by the client. Secondly, the client simply might not know what the file type actually is and just report 'application/octet-stream' instead.
you'll have to determine what kind of file was uploaded yourself. Fortunately, PHP provides the fileinfo extension, which can help you with determining the type of a file.
Code example based on one from php.net:
<?php
$finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
echo finfo_file($finfo, $_FILES["file"]["tmp_name"]) . "\n";
finfo_close($finfo);
?>
http://www.php.net/manual/en/ref.fileinfo.php

Try inspecting the MIME type being passed to you when you upload a file of that type. Insert a temporary print $_FILES["file"]["type"]; somewhere in your code, then upload the file to run the code and see what it prints out! You can then copy that type and use it in your if-statement.

Related

Can PHP's getimagesizefromstring method be trusted for mime type [duplicate]

Checking for mime type in php is pretty easy but as far as I know mime can be spoofed. The attacker can upload a php script with for example jpeg mime type. One thing that comes to mind is to check the file extension of the uploaded file and make sure it matches the mime type. All of this is assuming the upload directory is browser accessible.
Question: Are there any other techniques for preventing "bad files" from getting in with mime type spoofing?
Short answer: No.
Longer answer:
Comparing the extension and making sure that it matches the MIME type doesn't really prevent anything. As was said in the comments, it's even easier to modify a file extension. MIME type and extension are only to be meant as hints, there's no inherent security in them.
Ensuring that incoming files do no harm is very dependent on what your purpose for them is going to be. In your case I understood that you are expecting images. So what you could do is perform some sanity checks first: scan the first couple of bytes to see if the files contain the relevant image header signatures - all relevant image formats have these.
The "signature headers" help you to decide what kind of image format a file tries to impersonate. In a next step you could check if the rest of the contents are compliant with the underlying image format. This would guarantee you that the file is really an image file of that specific format.
But even then, the file could be carefully crafted in a way that when you display the image, a popular library used to display that image (e.g. libpng etc.) would run into a buffer overflow that the attacker found in that library.
Unfortuantely there's no way to actively prevent this besides not allowing any input from the client side at all.
Caution - this answer is now obsolete
The documentation for getimagesize explicitly states "Do not use getimagesize() to check that a given file is a valid image.
In case of Images
Check the extension with a list of allowed ones (ex. ".jpg", ".jpeg", ".png")
Check the uploaded file itself by running getimagesize on the file, it will return FALSE if it's not an image.
Other types of upload
Check the allowed extensions (ex. ".pdf")
Check that the mime type of the file corresponds to the extension
Sample code:
function getRealMimeType($filename) {
$finfo = new finfo(FILEINFO_MIME, "/usr/share/misc/magic");
if (!$finfo) {
echo "Opening fileinfo database failed";
return "";
}
return $finfo->file($filename);
}
See finfo_file documentation.
"mime_content_type" and "exif_imagetype" should not be used for security purposes because both of them allow spoofed files!
More details from link below:
https://straighttips.blogspot.com/2021/01/php-upload-spoofed-files.html
File extension check in order to block dangerous file extensions such as ".php" is the best way to go if files are going to be uploaded somewhere in the "public_html" folder!
Antivirus scan may be a nice alternative because some spoofed files are detected by antivirus!
Check the extension.
<?php
$okFiles = array('jpg', 'png', 'gif');
$pathInfo = pathinfo($filename);
if(in_array($pathInfo['extension'], $okFiles)) {
//Upload
}
else {
//Error
}
?>
You can also - like you said - check if the extension match the MIME type, but it's much more easy to just check the extension.
Btw why do you care about the MIME type?

using php to check if a file is a kml file

I am using move_file_upload on my server side in php so that client can allow users to upload their kml files to the server. I know that in order to check an image , in php I can use $check = getimagesize(file) but what would be the equivalent for a kml file check ?
I donot want to just check the extension of the file. I wish to know if infact the file is a valid kml file or not. If I only check the extension, someone can just post some other malicious file and change its extension to .kml
If you want to see if the file has the extension KML, you can use:
$filename = $_FILES["file"]["name"]; //or however you are getting the filename
$ext = end((explode(".",$filename)));
if($ext!="kml"){
//Extension is incorrect
}
Checking mime content can be helpful.
I am not quite sure what is the correct mime name of kml files but at least with checking in google it should be something as:
mime_content_type ($file) === 'application/vnd.google-earth.kml+xml'
How ever its possible that there are mimes set to 'application/xml' or 'text/xml' so extension validation is required as well ..

MIME Type spoofing

Checking for mime type in php is pretty easy but as far as I know mime can be spoofed. The attacker can upload a php script with for example jpeg mime type. One thing that comes to mind is to check the file extension of the uploaded file and make sure it matches the mime type. All of this is assuming the upload directory is browser accessible.
Question: Are there any other techniques for preventing "bad files" from getting in with mime type spoofing?
Short answer: No.
Longer answer:
Comparing the extension and making sure that it matches the MIME type doesn't really prevent anything. As was said in the comments, it's even easier to modify a file extension. MIME type and extension are only to be meant as hints, there's no inherent security in them.
Ensuring that incoming files do no harm is very dependent on what your purpose for them is going to be. In your case I understood that you are expecting images. So what you could do is perform some sanity checks first: scan the first couple of bytes to see if the files contain the relevant image header signatures - all relevant image formats have these.
The "signature headers" help you to decide what kind of image format a file tries to impersonate. In a next step you could check if the rest of the contents are compliant with the underlying image format. This would guarantee you that the file is really an image file of that specific format.
But even then, the file could be carefully crafted in a way that when you display the image, a popular library used to display that image (e.g. libpng etc.) would run into a buffer overflow that the attacker found in that library.
Unfortuantely there's no way to actively prevent this besides not allowing any input from the client side at all.
Caution - this answer is now obsolete
The documentation for getimagesize explicitly states "Do not use getimagesize() to check that a given file is a valid image.
In case of Images
Check the extension with a list of allowed ones (ex. ".jpg", ".jpeg", ".png")
Check the uploaded file itself by running getimagesize on the file, it will return FALSE if it's not an image.
Other types of upload
Check the allowed extensions (ex. ".pdf")
Check that the mime type of the file corresponds to the extension
Sample code:
function getRealMimeType($filename) {
$finfo = new finfo(FILEINFO_MIME, "/usr/share/misc/magic");
if (!$finfo) {
echo "Opening fileinfo database failed";
return "";
}
return $finfo->file($filename);
}
See finfo_file documentation.
"mime_content_type" and "exif_imagetype" should not be used for security purposes because both of them allow spoofed files!
More details from link below:
https://straighttips.blogspot.com/2021/01/php-upload-spoofed-files.html
File extension check in order to block dangerous file extensions such as ".php" is the best way to go if files are going to be uploaded somewhere in the "public_html" folder!
Antivirus scan may be a nice alternative because some spoofed files are detected by antivirus!
Check the extension.
<?php
$okFiles = array('jpg', 'png', 'gif');
$pathInfo = pathinfo($filename);
if(in_array($pathInfo['extension'], $okFiles)) {
//Upload
}
else {
//Error
}
?>
You can also - like you said - check if the extension match the MIME type, but it's much more easy to just check the extension.
Btw why do you care about the MIME type?

file upload in php

I am using php upload function to upload the files in my interface. I am using firefox-3.6.11 in my browser. I am uploading excel sheets. I have tried to get the uploaded file type.I have tested the file type with following way,
$Type = $HTTP_POST_FILES['TS_FILE']['type'];
$Data = split ("/", $Type,2 ) ;
if( "$Data[1]" != "vnd.ms-excel" && $Data[1]!="octet-stream" && "$Data[1]"!="xls" && "$Data[1]" != "excel" )
{
echo "<script> //alert ( 'inside alert' ) ;
alert ( 'The selected file is not in .xls format. Please select proper file.' ) ;
</script>";
exit;
}
It works fine. But some time I got the alert message as I mentioned in my code even if I upload the excel sheet. I don't know what is the exact problem. Is there any other excel file type is available in firefox versions???
The value of $_FILES['file']['type'] is sent by the browser, and the browser gets this value from the underlying OS. If I configure windows and tell it that .xls have mime type image/jpeg, my browser (be it firefox, IE or whatever) would send that type to your application.
So, basically, don't rely on $_FILES['file']['type'] to do the validation. Get this value yourself server-side using php's fileinfo:
$finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
$type = finfo_file($finfo, $_FILES['file']['tmpname']);
Also, you can get a list of used mimetypes for excel files from this site: http://filext.com/file-extension/XLS
edit: $_FILES instead of $_SERVER (sorry, it's early here)
I don't know where the error is in your code as I haven't uploaded files close to that way.
I've allways used the example on W3Schools http://w3schools.com/php/php_file_upload.asp
And then edited it heavily to make it process the right kind of files (wich is where you seem to be stuck).
The way you'd want to check the file type is using $_POST['file']['type']
I see that you are indeed using this but perhaps not correctly.
You can look on W3S how they do file type checking for images, this can also be used for xls.
The way to find out what your browser sends as file type is to simply trigger_error("File type is: ".$_POST['file']['type']);
Now you can make an if statement as they used on W3S to validate the file using the file type the trigger_error reported.
Please be aware that some browsers (especially IE) could use a different name.
(sorry for not being able to give you an answer to your own script but perhaps there are some things I said that might help)

Verifying mime type of pdf files on upload in PHP

I am working on a project that requires file uploads. I want to make sure it's secure and that only PDF files are being uploaded. I am already checking file extension but i want to make sure the file really is a pdf file.
What is the best way to check the mime type in php? I am using PHP 5.2.5 and can't seem to get fileinfo or mime_content_type() working.
for fileinfo i keep getting this:
Warning: finfo_open() [function.finfo-open]: Failed to load magic database
at '(null)'. in [snipped filename] on line 35
mime types are not reliable for checking type of files. A client's browser might report it wrongly.
Check for Magic Number. PDF files start with "%PDF" (25 50 44 46).
Indeed, MIME type's aren't the best way of making sure that a user has uploaded a valid file since this can be easily faked if you know how.
But when the file is being posted, you can always check the mime type this way:
$Type = $_FILES['someFile']['type'];
Maybe you could use a php class to determine it's a valid PDF something like FPDF( http://www.fpdf.org/)
Well, good luck anyways :)
It probably means that the MAGIC environment variable is not set, and your magic file isn't at /usr/share/misc/magic . Either set the value of MAGIC to point to the correct magic file, or pass the magic file as a second parameter to your finfo constructor
$finfo = new finfo(FILEINFO_MIME, "/usr/share/misc/magic");
or
$finfo = finfo_open(FILEINFO_MIME, "/usr/share/misc/magic");
An easy way to get the MIME type is directly from $_FILES.
If the mime type contains the word 'pdf' then you can consider it a valid PDF.
$contentType = $_FILES['myFile']['type'];
if(isValidPDF($contentType)) {
die('It is a PDF');
} else {
die('It is not a PDF');
}
function isValidPDF($mime) {
return strpos($mime, 'pdf') !== false;
}

Categories