<tutorialjinni.com/>

Secure File Upload in PHP

Posted Under: PHP, Programming, Security on Feb 11, 2016
Secure File Upload in PHP
Almost all of the modern web application incorporate the functionality of file upload. It may range from a user display picture or a document that may be share across all member of a team. A file when uploaded to a server it should be treated as "containment" and through checks should be implemented to check it. If a file upload is taken lightly it may compromise the entire server which cause a devastating effect on an organization's business. This tutorial aimed to point out ways by which an upload an be secured on server.

All example code given are in PHP but they can be easily translated in language.

Considerations for File Upload

Change File Name & Extension

It is recommended that file names of the uploaded file should be changed so that it wont be predicted by the up-loader. A simple approach would be to rename it after upload with the hash's value, hash can be either MD5 or SHA-1. A simple code will as follows.
$salt="A_DASH_OF_SALT_AND_PEPP3R_WOULD_BE_NICE";
echo $filename=md5(microtime(true).$salt);
// Sample output = 7f269157e5902f29271c07e26bb622e3;
It is advised that you should remove extensions altogether.

Save File Outside Document Root

Saving file outside Document Root so it cannot be accessed directly. This technique some times refer to as "File Firewall". When file is required it should be read by PHP function readfile() and stream to the user. However it is not always possible as in shared hosting environments access beyond your root directory is not given.

Limit File Size

It is a good idea to limit the size of the uploaded file. Too large file may fill the entire space on the server or take too much time of the PHP script in uploading.

Scan File for Malware

Every file that is uploaded should be checked for malware presence. If you have owned a server and able to install software then ClamAV will be a good starting point. If you can not do that then you can check the it on Virus total using its free API. Both techniques will be discussed in their own tutorials, very soon.
[Update] Scan using Vriustotal API can be found here Virustotal API File Scanning PHP Example

Authentication Before File Uploads

All files uploaded to a server must be done after the authentication of the user. This will ensure that only a valid user can upload a file and if problem occur it can be traced back.

Limit the Number of Upload File by a User

There should be a limit on how much a file a user can upload. This is usually forgotten by the developers.

Validate Input

Never trust the user supplied data always validate each and every thing that is coming from users.

Check File MIME type

Always check file mime type to check what really it is. Never rely on user provided MIME, instead check it using the below mentioned code

echo mime_content_type('php.gif') . "n";
echo mime_content_type('test.php');
// OUTPUTS
// image/gif
// text/plain
To use this function you need to enable php_fileinfo extension.

PHP Secure File Upload Example

First the HTML Part:
<!DOCTYPE html>
<html>
<body>
<form action="" method="post" enctype="multipart/form-data">
    Select file to upload:
    <input type="file" name="fileToUpload" id="fileToUpload">
    <input type="submit" value="Upload File" name="submit">
</form>
</body>
</html>
Now the PHP part:
<?php 

// AUTHENTICATION CODE GOES HERE...

if(isset($_POST["submit"])){
    $salt="A_DASH_OF_SALT_AND_PEPP3R_WOULD_BE_NICE";  
    $uploadFolder="UNCOMMON_NAMED_FOLDER/";
    $newName=md5(microtime(true).$salt);
    $destination=$uploadFolder.$newName;
    $maxUploadSize=1048576; // 1 MB Limit
    $mimeArray=array("image/gif","text/plain");
    
    //Check User Files Limit here
    
    if($_FILES['fileToUpload']['error'] == 0){
        if($_FILES["fileToUpload"]["size"] < $maxUploadSize){
            
            //ClamAV Checking code here
            // or
            //Virustotal Checking here
            
            //MIME Checking
            $mime=mime_content_type($_FILES['fileToUpload']['tmp_name']);
            if(in_array($mime, $mimeArray)===FALSE){
                echo "MIME Not Allowed";
                //Exit Code;
                exit;
            }
            if(move_uploaded_file($_FILES['fileToUpload']['tmp_name'],$destination)){
                echo "File Uploaded Sucessfuly";
                exit;
            }else{
                echo "Cannot upload file, Please Check Server Conf.";
                exit;
            }
        }else{
            echo "Too large file";
            exit;
        }
    }else{
        echo "There are problem with the upload, Try again!";
        exit;
    }
}
?>


imgae