安全图像上传PHP

时间:2013-06-05 11:39:51

标签: php mysql file-upload

在我的网站上,我允许用户使用以下内容上传图片...

$max_filesize = 1572864; // 1.5MB
$upload_path = 'uploads'; 
$upload_path = $upload_path.'/';

$filename = $_FILES['profile_image']['name']; 


if(filesize($_FILES['profile_image']['tmp_name']) > $max_filesize)
      die('The file you attempted to upload is too large.'); 
if(!is_writable($upload_path))
      die('permission errorrr!'); 

if(move_uploaded_file($_FILES['profile_image']['tmp_name'],$upload_path . $filename)){
    // TA DA!
}

我刚刚接受了一些有关如何安全的信息,以及如何使其更加安全,我问我已经设法将.png文件更改为.jpg并上传它,所以理论上可以.exe被重命名和上传,如果是这样,怎么能被反击?

6 个答案:

答案 0 :(得分:2)

Mime类型不可信任,因此,正如@yoeriboven所说,你可以使用:

if (!getimagesize($_FILES['profile_image']['tmp_name'])){
    die('Not an image');
}

但您也不能允许执行上传到您的uploads文件夹的任何文件。您可以通过.htaccess(假设您正在使用Apache)执行此操作:

AddHandler cgi-script .php .pl .py .jsp .asp .htm .shtml .sh .cgi
Options -ExecCGI

为了帮助用户,您可以做的另一件小事是使用HTML5的accept属性:

<input type="file" name="file" accept="image/gif, image/jpeg" />

(显然上面的内容可以在客户端更改,因此不能依赖它)

答案 1 :(得分:2)

您可以先检查文件扩展名,但有些人可能会尝试伪造它:

ForceType application/octet-stream
<FilesMatch "(?i)\.jpe?g$">
    ForceType image/jpeg
</FilesMatch>
<FilesMatch "(?i)\.gif$">
    ForceType image/gif
</FilesMatch>
<FilesMatch "(?i)\.png$">
    ForceType image/png
</FilesMatch>

此代码放在上传目录中的.htaccess文件中,只允许图像与其默认处理程序相关联。其他所有内容都将作为普通字节流提供,不会运行任何处理程序。 (查看此文章[1]

答案 2 :(得分:1)

我认为.exe文件无法重命名。否则它将成为损坏的文件,因此不建议重命名.exe文件,并在php文件上传数据使用post方法,因此数据不可见,因此它是安全的。

答案 3 :(得分:1)

你可以用这个例子。如果它不是图像,它将返回false:

if (!getimagesize($_FILES['profile_image']['tmp_name'])){
    die('Not an image');
}

答案 4 :(得分:1)

你关注的不是exe可以上传(因为有办法绕过任何安全性,甚至是MIME)但是这个exe可以稍后执行(只是上传一个exe文件不会执行它,它只会躺在那里)?

但是如果你想保护它,我建议reading up on MIME types并继续它。强制执行文件扩展也是一种方式(因此MIME图像/ png将被更改,因此扩展名为.png而不是用户放置的任何内容)。

答案 5 :(得分:0)

这是我之前用过我的图片上传器的功能。 它将检查jpeg文件的幻数并返回true或false。

function checkMagicNumberJPEG ($filename) {
    // Open file and read first 2 btytes
    $file = fopen($filename, 'r');
    $contents = fread($file, 2);

    $ascii = '';

    // Convert to hex
    for ($i = 0; $i < strlen($contents); $i++) { 
        $ascii .= dechex(ord($contents[$i])); 
    }

    // Close file
    fclose($file);

    // Check magic number
    if($ascii == 'ffd8') {
        return true;
    } else {
        return false;
    }
}