Safe way to upload image in php and htaccess

I found the following code on the web to securely upload images to php.

I want to know that it covers all possible attack methods when loading images.

define('MAX_SIZE_EXCEDED', 101); define('UPLOAD_FAILED', 102); define('NO_UPLOAD', 103); define('NOT_IMAGE', 104); define('INVALID_IMAGE', 105); define('NONEXISTANT_PATH', 106); class ImgUploader { var $tmp_name; var $name; var $size; var $type; var $error; var $width_orig; var $height_orig; var $num_type; var $errorCode = 0; var $allow_types = array(IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG); function __construct($fileArray) { foreach($fileArray as $key => $value) { $this->$key = $value; } if($this->error > 0) { switch ($this->error) { case 1: $this->errorCode = MAX_SIZE_EXCEDED; break; case 2: $this->errorCode = MAX_SIZE_EXCEDED; break; case 3: $this->errorCode = UPLOAD_FAILED; break; case 4: $this->errorCode = NO_UPLOAD; break; } } if($this->errorCode == 0) { $this->secure(); } } function secure() { //$this->num_type = exif_imagetype($this->tmp_name); @list($this->width_orig, $this->height_orig, $this->num_type) = getimagesize($this->tmp_name); if(filesize($this->tmp_name) > 1024*1024*1024*5) // allows for five megabytes. Change this number if need be. { $this->errorCode = MAX_SIZE_EXCEDED; return false; } if (!$this->num_type) { $this->errorCode = NOT_IMAGE; return false; } if(!in_array($this->num_type, $this->allow_types)) { $this->errorCode = INVALID_IMAGE; return false; } } function getError() { return $this->errorCode; } function upload_unscaled($folder, $name) { return $this->upload($folder, $name, "0", "0"); } function upload($folder, $name, $width, $height, $scaleUp = false) { // $folder is location to be saved // $name is name of file, without file extention // $width is desired max width // $height is desired max height if($this->errorCode > 0) return false; // deal with sizing // if image is small enough to not scale, or upload_unscaled() is called, don't scale if((!$scaleUp && ($width > $this->width_orig && $height > $this->height_orig)) || ($width === "0" && $height === "0")) { $width = $this->width_orig; $height = $this->height_orig; } else { // if height diff is less than width dif, calc height if(($this->height_orig - $height) <= ($this->width_orig - $width)) $height = ($width / $this->width_orig) * $this->height_orig; else $width = ($height / $this->height_orig) * $this->width_orig; } // Resample switch($this->num_type) { case IMAGETYPE_GIF: $image_o = imagecreatefromgif($this->tmp_name); $ext = '.gif'; break; case IMAGETYPE_JPEG: $image_o = imagecreatefromjpeg($this->tmp_name); $ext = '.jpg'; break; case IMAGETYPE_PNG: $image_o = imagecreatefrompng($this->tmp_name); $ext = '.png'; break; } $filepath = $folder.(substr($folder,-1) != '/' ? '/' : ''); if(is_dir($_SERVER['DOCUMENT_ROOT'].$filepath)) $filepath .= $name.$ext; else { $this->errorCode = NONEXISTANT_PATH; imagedestroy($image_o); return false; } $image_r = imagecreatetruecolor($width, $height); imagecopyresampled($image_r, $image_o, 0, 0, 0, 0, $width, $height, $this->width_orig, $this->height_orig); switch($this->num_type) { case IMAGETYPE_GIF: imagegif($image_r, $_SERVER['DOCUMENT_ROOT'].$filepath); break; case IMAGETYPE_JPEG: imagejpeg($image_r, $_SERVER['DOCUMENT_ROOT'].$filepath); break; case IMAGETYPE_PNG: imagepng($image_r, $_SERVER['DOCUMENT_ROOT'].$filepath); break; } imagedestroy($image_o); imagedestroy($image_r); return '/'.$filepath; } } 

I also have a .htaccess file stored in the "images" folder, which disables the file scripts, so no one can execute scripts in the photo folder.

 <Files ^(*.jpg)> order deny,allow deny from all </Files> Options -Indexes Options -ExecCGI AddHandler cgi-script .php .php3 .php4 .php5 .phtml .pl .py .jsp .asp .htm .shtml .sh .cgi 

does this enough for security reasons, or I need to take some other steps to protect my code and website.

+8
php image-uploading
source share
5 answers

The first thing I will say is to check file types using Apache mod_mime , otherwise I can send an HTTP request that says I'm a JPEG file! and you just trust the file extension, for example, Yeap! you have the extension .jpg, but in fact I can enter the PHP source code instead of the JPEG data, and later I can execute the PHP source code on your server.

Another thing is to always force Apache to NOT run any of these types of images. This can be done using ForceType directives.

 <FilesMatch "(?i)\.jpe?g$"> ForceType image/jpeg </FilesMatch> 

Edit:

I did not see the bottom lines. Disabling file scripts will absolutely help.

+7
source share

Is this code protected?

Php

In short, no, not necessarily! There is one fatal flaw that the code does not cover, but do not despair, it is very easily resolved!

While the script is testing the file extension, it does not test the MIME file type and therefore can potentially open up a whole world of problems.

Besides this minor vulnerability, the code is pretty safe.

Apache

Faking an HTTP request to look like JPEG is very simple, and while PHP can handle it, it is sometimes better to ensure that the vulnerability is covered in all angles. A simple fix using the MOD_MIME module in Apache can be used to fix this flaw, as described below.

HTTPS - Perhaps Irrelavent

If you are worried that these files are sniffed between the client and server, the use of an SSL certificate on your website is an absolutely important part of your security. This will encrypt all data between the client and server.

However, if the server side of things just bothers you, this is not necessary, although it is recommended.

Possible solutions

finfo() function

The finfo() function will return the MIME type of the file and, therefore, indicate whether it is a JPEG and can be loaded.

See here for more information on this feature.

Alternative alternative

Personally, I prefer to use the Colin column loading class. This class is extremely easy to use, covers all possible security problems, has a huge set of advanced functions using the GD library and is constantly maintained.

Visit the Colin Verot website here to download and start using the class.

Apache MOD_MIME

The Apache MOD_MIME module will force you to check the type of MIME files sent to the server.

Look here for more information.

+3
source share

The code seems to be good and the answer is primarily nice too, I just want to add another security question:

  • you must store the files in a directory that is outside the root of the document (not accessible through an HTTP request) and serve them through a script that first checks for proper authorization.
+1
source share

Since you have disabled all interpretation of files on the server, only the file name remains. If you create your own names or filter your usernames well, you have nothing to worry about.

Well .. almost nothing. There may be a security error in the GD library, so when using a malicious image, there might be something bad when resizing. But you cannot handle PHP, so upgrade your server.

0
source share

If you don't mind using your existing PHP loading system, this jQuery / PHP loading environment is extremely customizable and awesome.

http://blueimp.github.com/jQuery-File-Upload/

-one
source share

All Articles