Jump to content

Archived

This topic is now archived and is closed to further replies.

bqallover

Secure File Uploads

Recommended Posts

Hello all,

I need some advice on the most secure way to upload (in this case image files) from a PHP script. The script will be in an '/admin' directory which will be password-protected, but the destination directory (an image gallery) will not be protected. I already have this working, but it involves making the gallery world-writeable. (I'm testing on a standard install of Fedora Core 4). Does having this gallery world-writeable pose a security risk? I imagine it does!

My other idea would be to use the ftp functions instead, making use of my webhost FTP account to authorize the upload. Is this going too far or is there is a simpler way to perform a secure upload to a non-world-writeable directory? BTW, I'm not using a DB for this. Any help would be appreciated, as I have been looking into this for a while.

Share this post


Link to post
Share on other sites
Right let me rephrase this question.

If a directory on my site is 777, how would someone go about uploading to it? Would they have to compromise one of my scripts (code injection, Cross-site scripting, etc.) or could they simply anonymously FTP to it and upload? This is really holding me back and I'm sure it's elementary knowledge.

Cheers.

Share this post


Link to post
Share on other sites
[!--quoteo(post=360376:date=Mar 31 2006, 03:26 PM:name=bqallover)--][div class=\'quotetop\']QUOTE(bqallover @ Mar 31 2006, 03:26 PM) [snapback]360376[/snapback][/div][div class=\'quotemain\'][!--quotec--]
Right let me rephrase this question.

If a directory on my site is 777, how would someone go about uploading to it? Would they have to compromise one of my scripts (code injection, Cross-site scripting, etc.) or could they simply anonymously FTP to it and upload? This is really holding me back and I'm sure it's elementary knowledge.

Cheers.
[/quote]

i believe that the only way to upload a file to your server is via sloppy coding of your upload script. if it's secure, then no extra files will be uploaded.
here's a few points just incase you're paranoid or not:

1, rename the admin directory to something a little less obvious. whilst it doesn't really matter, it shows that you're predictable, just like people who use their dogs/kids/wife's/boyfriends name as a password.

2, there are ways (not too complex either), especially with images, to keep the files outside of the web tree altogether. it means that without a script (which you can bullet-proof as much as you like) there's no way to access certain content.

3, before you do anything with a file uploaded via your form, make sure that you THOROUGHLY scrutinize EVERY element of $_FILES. including 'size', 'type', everything. leave no room for anything you can consider slightly unwanted. if i wanted to p*ss someone off, and i knew the script would let me, i'd be happy enough to upload a several GB file. bye bye goes all your bandwidth and loads (if not all) of your disk space allowance for the month. yet it's still surprising how many people don't check for the size of a file before accepting it with open arms.

4, elaborating on point 3 above, DO NOT rely on the extension of the file to tell you what the file contains. there's nothing wrong with you checking, but check $_FILES['whatever']['type'] to make sure that the filetype is the sort of file youre happy to accept.

i'm sure there's points that would stretch my list into hundreds of things ,but these are the ones i always start with.

hope it helps
cheers

Share this post


Link to post
Share on other sites
Cheers man, that's some good help. I do tend to me more paranoid than not when it comes to such things!

On your points...

1) Good point. Will-do, though as you say, it doesn't [b]really[/b] matter.

2) I don't have access to anything outside the web-tree with my provider, just my web space. So no cigar for me :)

3) Yeah, I'm down with all that.

4) I think you can spoof $_FILES['whatever']['type'], as it's just the MIME type sent by the browser. Though I haven't tried this.

Thanks again. It was really just being sure that even with 777 on a directory, only a shoddy script could be used to upload by a malicious user, not some standard technique. Nice one :)

Share this post


Link to post
Share on other sites
[!--quoteo(post=360399:date=Mar 31 2006, 05:14 PM:name=bqallover)--][div class=\'quotetop\']QUOTE(bqallover @ Mar 31 2006, 05:14 PM) [snapback]360399[/snapback][/div][div class=\'quotemain\'][!--quotec--]
2) I don't have access to anything outside the web-tree with my provider, just my web space. So no cigar for me :)
[/quote]

very rare that you can't access at least one level outside of your root. most hosts provide you with access to at LEAST the level directly under your public_html/whatever folder.

[!--quoteo(post=360399:date=Mar 31 2006, 05:14 PM:name=bqallover)--][div class=\'quotetop\']QUOTE(bqallover @ Mar 31 2006, 05:14 PM) [snapback]360399[/snapback][/div][div class=\'quotemain\'][!--quotec--]
4) I think you can spoof $_FILES['whatever']['type'], as it's just the MIME type sent by the browser. Though I haven't tried this.
[/quote]
not sure about this one, if i'm honest. but as with most things, it's one less thing to be concerned about and one less thing for someone to take advantage of, i guess.

Cheers
Mark

Share this post


Link to post
Share on other sites
I've just got a basic 1&1 package, no root shells or anything. I just ftp to my domains when doing maintenance or what-have-you.

Cheers.

Share this post


Link to post
Share on other sites
i've actually been working on putting together some secure code for handling file uploads. i'm also trying to validate an image file that gets uploaded. here's the code that i have so far:

[code]
//This section of code handles the image file upload.
//First we verify that something was uploaded.
if (($_FILES['picture']['size'] != 0) && ($_FILES['picture']['tmp_name'] != ''))
{
    //checks and sees if there were any errors during the upload process
    if ($_FILES['picture']['error'] > 0)
    {
        switch ($_FILES['picture']['error'])
        {
            //file size is greater than that allowed by PHP as set in php.ini
            case 1:    errorcheck(1, '<B>File size exceeded maximum allowable file size of 100k.</B><P>'); break;
            //file size is greater than that allowed by MAX_FILE_SIZE as set in form
            case 2: errorcheck(1, '<B>File size exceeded maximum allowable file size of 100k.</B><P>'); break;
            case 3: errorcheck(1, '<B>File only partially uploaded.</B><P>'); break;
            case 4: errorcheck(1, '<B>No file uploaded.</B><P>'); break;
            default: errorcheck(1, '<B>An unknown file upload error occurred.</B><P>'); break;
        }
        exit;    
    }
    
    //need to check and make sure file MIME type is acceptable
    if (($_FILES['picture']['type'] != 'image/jpeg') && ($_FILES['picture']['type'] != 'image/jpg') && ($_FILES['picture']['type'] != 'image/gif') && ($_FILES['picture']['type'] != 'image/pjpeg'))
    {
        errorcheck(1, '<B>File is not of correct type. <BR />Valid file types are ".JPG", ".JPEG", or ".GIF".</B><P>');
    }

    //this is a simple quick test. if accessing the picture is impossible,
    //or if it isn't a valid picture, getimagesize() will return FALSE.
    if (!getimagesize($_FILES['picture']['tmp_name']))
    {
        errorcheck(1, '<B>File is not of correct type. <BR />Valid file types are ".JPG", ".JPEG", or ".GIF".</B><P>');
    }
    
    //checks if picture is an uploaded file
    if (is_uploaded_file($_FILES['picture']['tmp_name']))
    {
        //pathname for where we're moving file
        $picpath = '/home/virtual/site109/fst/var/www/html/uploadtmp/'.$_FILES['picture']['name'];
        
        //checks if file size is less than 100k
        if (filesize($_FILES['picture']['tmp_name']) <= 102400)
        {
            //double-checking filetype as the 'type' field check from above
            //isn't always reliable or secure
            $name = $_FILES['picture']['name'];
            $temparray = explode(".", $name);
            $ext = array_pop($temparray);
            if (($ext != "jpg") && ($ext != "jpeg") && ($ext != "JPG") && ($ext != "JPEG") && ($ext != "gif") && ($ext != "GIF"))
            {
                errorcheck(1, '<B>File is not of correct type. <BR />Valid file types are ".JPG", ".JPEG", or ".GIF".</B><P>');
            }

            //moving file to location specified by $picpath
            if (!move_uploaded_file($_FILES['picture']['tmp_name'], $picpath))
            {
                //encrypting email address to avoid spam-bots
                $support = email_encrypt('support@ofre.com');
                
                //composing error message for file not being moved properly
                $errormsg = '<B>There was a problem processing the image file that was uploaded.<BR /> Please try again.  If problem persists, continue without uploading a picture,<BR /> and email the image separately as an attachment to '.$support.'.';
                errorcheck(1, $errormsg);
            }
        }
        //if it's not less than 100k
        else
        {
            errorcheck(1, "<B>File size has exceeded maximum allowable file size of 100k.</B><P>");
        }
    }
    //if file is not a uploaded file, but something is there
    else
    {
        $errormessage = 'Possible file upload attack with file: '.$_FILES['picture']['name'];
        trigger_error($errormessage, E_USER_ERROR);
    }
    
    //if file is uploaded successfully, then it falls through all the if/else
    //statments and ends up here which means that we have a successful upload.
    $uploadsuccess = 1;
}
//need to check if no file was selected for upload from our form or if nothing was
//uploaded because it exceeded the constant MAX_FILE_SIZE
else
{
    if (isset($_FILES['picture']['name']))
    {
        if ($_FILES['picture']['name'] != '')
        {
            errorcheck(1, "<B>File size has exceeded maximum allowable file size of 100k,<BR />and might or might not be the correct file type.</B><P>");
        }
    }
}
[/code]


Let me know what you think...

Share this post


Link to post
Share on other sites

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.