PHP Protect Temp Files for Download

I'm a semi-newbie in PHP, and I'm starting to dive into file uploads. I create files with .xlsxand .csvusing PHPExceland place them in the temp directory for download. I found a good script to load, and I added some settings that I need. the script is below. I already read these posts:

Safe file upload in PHP, prevent the user without permission ... as well ... Protected files for download ... as well ... http://www.richnetapps.com/the-right-way-to-handle- file-downloads-in-php /

download.php

<?php

/*====================
START: Security Checks
====================*/

//(1) Make user it an authenicated/signed in user with permissions to do this action.
require("lib_protected_page.php");

//(2) Make sure they can ONLY download .xlsx and .csv files
$ext = pathinfo($_GET['file'], PATHINFO_EXTENSION);
if($ext != 'xlsx' && $ext != 'csv') die('Permission Denied.');

//(3) Make sure they can ONLY download files from the tempFiles directory
$file = 'tempFiles/'.$_GET['file'];

//ABOUT ITEM 3 - I still need to change this per this post I found....
/*
http://www.richnetapps.com/the-right-way-to-handle-file-downloads-in-php/

You might think you’re being extra clever by doing something like
$mypath = '/mysecretpath/' .  $_GET['file'];
but an attacker can use relative paths to evade that.
What you must do – always – is sanitize the input. Accept only file names, like this:
$path_parts = pathinfo($_GET['file']);
$file_name  = $path_parts['basename'];
$file_path  = '/mysecretpath/' . $file_name;
And work only with the file name and add the path to it youserlf.
Even better would be to accept only numeric IDs and get the file path and name from a
database (or even a text file or key=>value array if it’s something that doesn’t change
often). Anything is better than blindly accept requests.
If you need to restrict access to a file, you should generate encrypted, one-time IDs, so you can be sure a generated path can be used only once.
*/

/*====================
END: Security Checks
====================*/

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="text/csv"; break;
            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 "xlsx": $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");
        //Now, the use of Cache-Control is wrong in this case, especially to both values set to zero, according to Microsoft, but it works in IE6 and IE7 and later ignores it so no harm done.
        header("Cache-Control: private",false); // required for certain browsers
        header("Content-Type: $ctype");
        header("Content-Disposition: attachment; filename=\"".basename($fullPath)."\";" );
        //Note: the quotes in the filename are required in case the file may contain spaces.
        header("Content-Transfer-Encoding: binary");
        header("Content-Length: ".$fsize);
        ob_clean();
        flush();
        readfile( $fullPath );
    }
else
    die('File Not Found');
}
?>

My questions...

  • ? , .xlsx .csv tempFiles. , -, ? , ?
  • tempFiles , (www.mySite.com/tempFiles), - ( , ), (www.mySite.com/tempFiles/iGuessedIt012345.csv). , ( Apache), script (download.php)?

! - , , , . , , php, . FYI, tempFiles. .

+3
5

, .

. , , .

:

$file = 'tempFiles/'.$_GET['file'];

"../../var/www/my-site/index.php", , $ index.php, , tempfiles/ /var/www.

, .

, - . (..) :

if (strpos($GET['file'], "..") !== false) {
  // file parameters contains ..
}

, Ashish, , , , . .

, , , - / .

+2

- , , , . tmp, tmp, , , ", , ".

pdf:

....
$content = $MyPDFCreator->getContent();

header('Content-Type: application/pdf');
header('Content-Length: '.strlen( $content ));
header('Content-disposition: inline; filename="downloadme.pdf"');
header('Cache-Control: public, must-revalidate, max-age=0');
header('Pragma: public');
header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT');

echo $content;
+2

- ( "" - webroot - ). ​​ , ;

/var
  /www
    /html
      /my-site
        index.php
        download.php
        ...
  /tmpFiles
   iGuessedIt012345.csv

- - tmpFiles/. download.php

, tmpFiles/, .htaccess :

deny from all

403 Forbidden , .

+1

, URL- . . , , , , .

, URL-:

http://www.somedomain.com/download.php?one_time_token=<some one time token>

URL- , . , , . . - .

0

An authenticated user can access the page (download.php), where he can view files in tempFiles

Set .htaccess to "deny from all" in tempFiles so that no one can directly access, and then in the download.php file, each file must be uploaded using a token, which is sad Ashish Awasthi

If you don't like tokens, can you do something like download? file = iGuessedIt012345.csv, but if you do so, use the regex in the white list to see if everything is correct!

Example:

$var="iGuessedIt012345.csv";

if (preg_match('#^[[:alnum:]]+\.csv$#i', $var)){
    echo "ok";
}else{
    echo "bad request";
}

example2:

$var="iGuessed_It-012345.csv";

if (preg_match('#^[a-zA-Z0-9\-\_]+\.csv$#i', $var)){
    echo "ok";
}else{
    echo "bad request";
}
0
source

All Articles