tags:

views:

75

answers:

3

I'm building a php file uploader and I've some issues with security. For example I don't want to allow ".php" file uploads. As I know the only way to check the file type is with $_FILES['file']['type'] and the value of it is browser dependent.

I check with multiple browsers and found that when selecting a regular .php file different browsers return these values:

firefox: application/x-download
chrome: text/plain
safari: text/plain
IE: text/plain
opera: application/octet-stream

I've also tried the same experiment with the regular .txt files and all browses return text/plain as the mime type.

So here's the problem, If I want to allow the .txt file upload what should I do to prevent .php file uploads?

+2  A: 

Don’t rely on the information the client sends. Even the media type the client sends can be forged.

If you don’t want to allow PHP files, just don’t allow files with the file extension .php or change it to .txt:

if (strtolower(strrchr($_FILES['file']['name'], '.')) == '.php') {
    // has file extension .php
}
Gumbo
A: 

Try the following. It is FAR from fool proof but its a quick check. it will block anything labeled .php (as it is on the client machine) so if they have something like 'do_evil.php.txt' it will allow it BUT (read the code notes)

$file_ext = substr($_FILES['userfile']['name'], -3);
if($file_ext == 'php') {
   //REJECT FILE
}
else {
   // allow upload and once the file has been upload to the temp directory
   // have a peice of code move the file to the final location and rename 
   // the file and specify a new file extension, using $file_ext as the extension
   // so even if the file was 'do_evil.php.txt' when it comes to rest at the 
   // final location it will be 'do_evil.txt' and thus treated by the server as a
   // text file and not PHP
}

I have used the above in the past with descent results. It is by no means bullet proof, but it should at least help. i think i might have some code lying around that does all of that, if you need it ill go looking for it but no promises i can find it

DBunting
This would also block just “php” or “foo.notphp”.
Gumbo
most people dont strip their file extensions (if they have one) and who is going to give a file a .not??? extension?but your right. like i said far from fool proof but its ment as a stop gap
DBunting
I prefer the following code to determine the extension:$extention = strtolower( end ( explode ('.', $_FILES['userfile']['name'])));
Yasser Souri
+1  A: 

Use the following function:

function Mime($path)
{
    $result = false;

    if (is_file($path) === true)
    {
        if (function_exists('finfo_open') === true)
        {
            $finfo = finfo_open(FILEINFO_MIME_TYPE);

            if (is_resource($finfo) === true)
            {
                $result = finfo_file($finfo, $path);
            }

            finfo_close($finfo);
        }

        else if (function_exists('mime_content_type') === true)
        {
            $result = preg_replace('~^(.+);.*$~', '$1', mime_content_type($path));
        }

        else if (function_exists('exif_imagetype') === true)
        {
            $result = image_type_to_mime_type(exif_imagetype($path));
        }
    }

    return $result;
}

This will return the proper mime type of any file.

Alix Axel
Neat code. Thanks.
Haluk