Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the most secure method for uploading a file?

People also ask

What is the most secure way to transfer files?

As a secure file transfer method, HTTPS is best for banking, sending payments, and transferring private or sensitive data from a user through a website. Any transfers requiring a password should only be sent using the HTTPS protocol.

What is secure upload?

Secure Upload is a tool for secure sharing of personal/sensitive data with external clients. The recipient will receive a secure download link which can only be unlocked with the password. If you enter the recipient's mobile phone number they will automatically receive a password via SMS.

Is uploading a file safe?

File uploads are generally intended to be inert. Unless you are building a very particular type of website, you are typically expecting images, videos, or document files, rather than executable code. If this is the case, making sure uploaded files are kept separate from application code is a key security consideration.


  1. Allow only authorized users to upload a file. You can add a captcha as well to hinder primitive bots.

  2. First of all, set the MAX_FILE_SIZE in your upload form, and set the maximum file size and count on the server as well.

    ini_set('post_max_size', '40M'); //or bigger by multiple files
    ini_set('upload_max_filesize', '40M');
    ini_set('max_file_uploads', 10);
    

    Do size check by the uploaded files:

    if ($fileInput['size'] > $sizeLimit)
        ; //handle size error here
    
  3. You should use $_FILES and move_uploaded_file() to put your uploaded files into the right directory, or if you want to process it, then check with is_uploaded_file(). (These functions exist to prevent file name injections caused by register_globals.)

    $uploadStoragePath = '/file_storage';
    $fileInput = $_FILES['image'];
    
    if ($fileInput['error'] != UPLOAD_ERR_OK)
        ; //handle upload error here, see http://php.net/manual/en/features.file-upload.errors.php
    
    //size check here
    
    $temporaryName = $fileInput['tmp_name'];
    $extension = pathinfo($fileInput['name'], PATHINFO_EXTENSION);
    
    //mime check, chmod, etc. here
    
    $name = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM)); //true random id
    
    move_uploaded_file($temporaryName, $uploadStoragePath.'/'.$name.'.'.$extension);
    

    Always generate a random id instead of using the original file name.

  4. Create a new subdomain for example http://static.example.com or at least a new directory outside of the public_html, for the uploaded files. This subdomain or directory should not execute any file. Set it in the server config, or set in a .htaccess file by the directory.

        SetHandler none
        SetHandler default-handler
        Options -ExecCGI
        php_flag engine off
    

    Set it with chmod() as well.

        $noExecMode = 0644;
        chmod($uploadedFile, $noExecMode);
    

    Use chmod() on the newly uploaded files too and set it on the directory.

  5. You should check the mime type sent by the hacker. You should create a whitelist of allowed mime types. Allow images only if any other format is not necessary. Any other format is a security threat. Images too, but at least we have tools to handle them...
    The corrupted content for example: HTML in an image file can cause XSS by browsers with content sniffing vulnerability. When the corrupted content is a PHP code, then it can be combined with an eval injection vulnerability.

    $userContent = '../uploads/malicious.jpg';
    include('includes/'.$userContent);
    

    Try to avoid this, for example use a class autoloader instead of including php files manually...
    By handling the javascript injection at first you have to turn off xss and content sniffing in the browsers. Content sniffing problems are typical by older msie, I think the other browsers filter them pretty well. Anyways you can prevent these problems with a bunch of headers. (Not fully supported by every browser, but that's the best you can do on client side.)

    Strict-Transport-Security: max-age={your-max-age}
    X-Content-Type-Options: nosniff
    X-Frame-Options: deny
    X-XSS-Protection: 1; mode=block
    Content-Security-Policy: {your-security-policy}
    

    You can check if a file is corrupted with Imagick identify, but that does not mean a complete protection.

    try {
        $uploadedImage = new Imagick($uploadedFile);
        $attributes = $uploadedImage->identifyImage();
        $format = $image->getImageFormat();
        var_dump($attributes, $format);
    } catch (ImagickException $exception) {
        //handle damaged or corrupted images
    }
    

    If you want to serve other mime types, you should always force download by them, never include them into webpages, unless you really know what you are doing...

    X-Download-Options: noopen
    Content-Disposition: attachment; filename=untrustedfile.html
    
  6. It is possible to have valid image files with code inside them, for example in exif data. So you have to purge exif from images, if its content is not important to you. You can do that with Imagick or GD, but both of them requires repacking of the file. You can find an exiftool as an alternative. I think the simplest way to clear exif, is loading images with GD, and save them as PNG with highest quality. So the images won't lose quality, and the exif tag will be purged, because GD cannot handle it. Make this with images uploaded as PNG too...
    If you want to extract the exif data, never use preg_replace() if the pattern or replacement is from the user, because that will lead to an eval injection... Use preg_replace_callback() instead of the eval regex flag, if necessary. (Common mistake in copy paste codes.) Exif data can be a problem if your site has an eval injection vulnerability, for example if you use include($userInput) somewhere.

  7. Never ever use include(), require() by uploaded files, serve them as static or use file_get_contents() or readfile(), or any other file reading function, if you want to control access.
    It is rarely available, but I think the best approach to use the X-Sendfile: {filename} headers with the sendfile apache module. By the headers, never use user input without validation or sanitization, because that will lead to HTTP header injection.
    If you don't need access control (means: only authorized users can see the uploaded files), then serve the files with your webserver. It is much faster...

  8. Use an antivir to check the uploaded files, if you have one.

  9. Always use a combined protection, not just a single approach. It will be harder to breach your defenses...


The best solution, IMHO, is to put the directory containing the uploaded files outside of the "web" environment and use a script to make them downloadable. In this way, even if somebody uploads a script it can not be executed by calling it from the browser and you don't have to check the type of the uploaded file.


Use and configure Hardened-PHP create a plain script using move_uploaded_file and the $_FILES superglobal. The simplest the script, the safest it will be (at least, as safe as the running PHP version itself)