Check upload file , accept only file zip formats - php

In my project , there is a possibility to download/upload a backup of the project (with some configuration/images etc etc).
I have to accept only backups in .zip format (for the upload) , for this i used this code for check the format (client side and server side)
client side , with jQuery form
var ftype=$('#FileInput')[0].files[0].type;
switch(ftype){
case 'multipart/x-zip':
break;
case 'application/zip':
break;
case 'application/x-zip-compressed':
break;
case 'application/x-zip':
break;
default: .... //error type
}
server side
switch(strtolower($_FILES['FileInput']['type'])){
case 'multipart/x-zip':
break;
case 'application/zip':
break;
case 'application/x-zip-compressed':
break;
case 'application/x-zip':
break;
default: exit("1");
}
Every O.S has a different manner to recognize a .zip file (in fact in the switch there isn't the application/octet-stream case , and for this i decided to ask about this because a user tell me this problem).
So , the question is : where i can find a doc about this , or something where i can find a list of the various manner in which the O.S recognize a .zip file.
thanks

Related

Understanding if a file is an image or a video from its content

I can not find a way to understand if a file is really a video or an image.
For example: I have a .jpg image renamed .mp4, if I open it via computer or browser I can not see anything because it is not really a video.
What I'm looking for is a way to understand if a video / image beyond the required extension is also really a video or an image, depending on the request.
In theory I would like a similar result:
$ImageOrVideo = pathinfo($_FILES["file"]["tmp_name"],PATHINFO_EXTENSION);
switch($ImageOrVideo){
case 'jpg': //check if a real image
case 'mp4': // check if a real video
default: exit('stop');
}
I had thought of some solutions, for example in the past I had used for the images getimagesize (), but now the php documentation says:
Caution This function expects filename to be a valid image file. If a
non-image file is supplied, it may be incorrectly detected as an image
and the function will return successfully, but the array may contain
nonsensical values.
Do not use getimagesize() to check that a given file is a valid image.
Use a purpose-built solution such as the Fileinfo extension instead.
$ImageOrVideo = $_FILES["file"]["tmp_name"];
switch(mime_content_type($ImageOrVideo)){
case 'image/jpeg':
// ........
break;
case 'video/mp4':
// ........
break;
default:
exit('stop');
}

Force image download - .php files download

this is my download.php;
session_start();
$file = $_GET['file'];
download_file($file);
function download_file( $fullPath ){
// Must be fresh start
if( headers_sent() )
die('Headers Sent');
// Required for some browsers
if(ini_get('zlib.output_compression'))
ini_set('zlib.output_compression', 'Off');
// File Exists?
if( file_exists($fullPath) ){
// Parse Info / Get Extension
$fsize = filesize($fullPath);
$path_parts = pathinfo($fullPath);
$ext = strtolower($path_parts["extension"]);
// Determine Content Type
switch ($ext) {
case "pdf": $ctype="application/pdf"; break;
case "exe": $ctype="application/octet-stream"; break;
case "zip": $ctype="application/zip"; break;
case "doc": $ctype="application/msword"; break;
case "xls": $ctype="application/vnd.ms-excel"; break;
case "ppt": $ctype="application/vnd.ms-powerpoint"; break;
case "gif": $ctype="image/gif"; break;
case "png": $ctype="image/png"; break;
case "jpeg":
case "jpg": $ctype="image/jpg"; break;
default: $ctype="application/force-download";
}
header("Pragma: public"); // required
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: private",false); // required for certain browsers
header("Content-Type: $ctype");
header("Content-Disposition: attachment; filename=\"".$_REQUEST["isim"]."\";" );
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".$fsize);
ob_clean();
flush();
readfile( $fullPath );
} else
die('File Not Found');
}
This is forced jpg download file. But this file can download all .php files.
Normaly i use this download link and download image;
http://domain.net/download.php?file=wp-content/uploads/2016/04/10/126379-fantasy_art.jpg
But then i tested this link download my config file...
http://domain.net/download.php?file=wp-config.php
I think this is big vulnerable.
How can i fix this? i dont want download any .php files...
Thanks..
Use default in your switch case to avoid this problem:
Remove this:
default: $ctype="application/force-download";
For this: default: die('File not found'); or default: return false;
Also you could check if path makes sense, like it should be a subfolder of uploads. This post has some info for you: Test if a directory is a sub directory of another folder
I think it would be good for you to step back and consider what this script actually does, because it is still a gigantic security hole. Here is what it does:
Take the user's input (which is always untrustworthy)
See if it's extension is allowed according to a small list of possible extensions
If so, pass it off to the user
Now that you have it die for unrecognized file extensions, it won't let them download your actual php files. But it will still let the user do all sorts of terrible things, all of which comes down to one very key issue:
You make no attempt to verify that the file being requested is actually reasonable for the person to view!!!
A key point is that readfile() doesn't care where the file is. Nor does it even assume that the file is in your website's public directory. The only reason it is downloading files from your web directory is because you didn't start the filename with a slash. However, readfile() will happily pass along anything on the server that it has read access to. Without your recent change a user could have just as easily done this:
http://domain.net/download.php?file=/etc/passwd
Moreover, it doesn't even have to be an actual file on the server. In most PHP installations PHP will happily load up URLs as actual files. So someone could also use your script as a proxy:
http://domain.net/download.php?file=http://theFBIwillArrestYouIfYouLoadThis.com/secrets.pdf
That sort of vulnerability (the ability to use your script as a proxy) is still present in your current solution. Anytime I see a website take file paths like this I love to see just how much it will let me get away with. You could set yourself up for a world of hurt in the worst case scenario.
You have to look at it from a defense-in-depth scenario. What it boils down to is the difference between blacklisting (what is the user not allowed to do) and whitelisting (what should this user be allowed to do). Good security practices rely on the latter method of thinking exclusively, because it is impossible to come up with a completely exhaustive blacklist that covers all possible scenarios.
In a case like this if you want a user to be able to download files you need some sort of list of files that are allowed to be downloaded. One example would be to place any file that is supposed to be downloaded into a specific directory. If a user requests a file then your script can use realpath() to make sure that file is actually in your public directory and otherwise forbid the download. Although if they are all in one directory you could just as easy change a configuration rule in your webserver (e.g. apache or nginx) to have it automatically add the 'content-disposition: attachment' header to anything in that directory. Then you just have to make sure that you never put the wrong files in that public directory.
Me personally though, I would approach it with a complete white-list. I would never let someone specify a filename and then use it to download a file. Rather I would have an administrative area where I manage files that are marked for download: the list of allowed files would be stored in the database and managed by me. When the user downloads a file they don't do it by specifying a filename but rather by specifying the id from the database that corresponds to the file they want to download (a simple user interface is necessary to facilitate this). The ID is used to lookup the file path, and the file can then be downloaded safely. You can then even store the files in directories outside the public area of your website so that you have full control over who can access the files.
That last suggestion is probably overkill for what you are trying to do, but the short of this is simple: you have to think carefully about the security implications of your code and make sure you are giving the user the minimum amount of privileges possible.

Imagecreatefromjpeg With Faulty File

im writing an script that resize and crops the uploaded images.
all valid files are ok...
but some of my visitors are trying to upload non-valid ones.. for example the file extension is jpg, but in fact its a tiff file .. the uploading file's extension looks gif, but in its exif details writes 'its a jpg'.. etc..
As you can imagine, imagecreatefromXX() functions are all giving error in that case (its not a valid jpg etc)..
do you have any idea, how may i solve this problem?
how must i modify my recent codes?
switch($type) {
case 'gif':
$img = imagecreatefromgif($source);
break;
case 'jpg':
case 'JPEG':
case 'jpeg':
$img = imagecreatefromjpeg($source);
break;
case 'png':
$img = imagecreatefrompng($source);
break;
}
Your best bet would probably be to modify the code that sets $type, rather than the code you've shared (though John Conde's suggestion to have a default case is a good one), and use something like exif_imagetype (which your question suggests might already be in play) to determine the type, rather than trusting the extension (which you may even want to change to the appropriate type when writing the file): the extension is user-supplied data, and as such, the least likely to be accurate and/or useful.
e.g.
$type = exif_imagetype($source);
switch ($type){
case IMAGETYPE_GIF:
$img = imagecreatefromgif($source);
break;
case IMAGETYPE_JPG:
$img = imagecreatefromjpeg($source);
break;
case IMAGETYPE_PNG:
... etc ...
default:
//Fail Gracefully
}

file upload not working for doc, excel file

I am using below code for file upload but it do not work in case of doc and excel file
switch(strtolower($ImageType))
{
case 'image/png':
case 'image/gif':
case 'application/pdf':
case 'image/jpeg':
case 'video/avi':
case 'video/mp4':
case 'image/pjpeg':
case 'application/msword':
case 'application/vnd.ms-excel':
break;
default:
die('Unsupported File!'); //output error and exit
}
this code work i case of image but when we upload doc file. it show me unsupported file
You are probably missing additional MIME types. Your MIME types are correct for older .doc and .xls files, but not for newer ones.
For .xlsx files use:
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
For .docx files use:
application/vnd.openxmlformats-officedocument.wordprocessingml.document
This might help you as well:
What is a correct mime type for docx, pptx etc?
What is correct content-type for excel files?

Best way to validate an upload form?

Which would be the best way to validate an upload form?
Using the mime type at the moment, but that's not quite working - can't upload mpegs even though am looking for video in the mime type.
Thank you
Tom
This seems to work:
switch (strtolower($_FILES["file"]["type"])){
case "application/msword":
case "application/pdf":
case "application/vnd.ms-excel":
case "application/vnd.ms-powerpoint":
case "application/zip":
case "image/gif":
case "image/jpeg":
case "image/png":
case "image/tiff":
case "text/plain":
case "video/mpeg":
case "video/x-mpeg2":
case "video/msvideo":
case "video/quicktime":
// do it
break;
default:
// don't do it
break;
}
For anyone else this might help have a look at http://www.sfsu.edu/training/mimetype.htm for adding other mime types you might need to check.
I guess you want to check if an uploaded file is a valid video-file. So one thing you can check is the file extension (IE ".mpg" for mpeg video). Because no webframework known to me has an internal video-validation, you have to rely on some external program/library to check if the video file is really a video-file. Maybe FFMPEG is able to do this.
Try something like so:
$mime = strtolower($_FILES["file"]["type"]);
$parts = explode("/",$mime);
switch($parts[0])
{
case 'video':
//Video file, use $parts[1] to check the video subtype
break;
case 'image':
break;
}

Categories