防止MIME伪造成php上传文件

时间:2020-03-06 14:40:04  来源:igfitidea点击:

有没有一种方法可以防止某人伪造文件上传的mime类型,然后运行php / exe / etc ...

我必须使文件上载目录可写且可执行,以便可以存储文件,但这允许任何人在以后运行脚本。我可以做的一件事是在文件名中添加随机数据,这样他们就不能再猜测文件名了(因为他们仍然无法从目录中读取列表)。

我是第一次使用php上传文件,并且试图涵盖所有安全问题。

解决方案

Web浏览器不应访问文件上传目录。 IE。不允许他人上传文件,说"remove_all_my_files.php",然后通过给它提供url来在系统上执行它,说"`http://xample.com/uploads/remove_all_my_files.php" "。

$ _FILES中的信息总是来自客户端,因此我们要做的就是接受文件并在服务器上进行扫描。我或者建议使用finfo,它是PHP扩展,因此很容易:

<?php
// example :-)
$finfo = finfo_open(FILEINFO_MIME);
echo finfo_file($finfo, '/path/to/your/upload/file);
finfo_close($finfo);
?>

如果我们不喜欢程序,也有一个OO接口。

如果没有finfo选项,则可以使用unix命令文件进行检查。

另外,许多人建议通过包装器提供文件。我对此感到不知所措,这可能是一个解决方案,但远非理想,因为a)文件仍在服务器上,b)提供这样的文件非常昂贵。

在我的Apache Web服务器配置上,我不相信实际的文件内容决定文件是否作为脚本运行。通过匹配文件结尾来确定是将文件显示为文本还是图像格式,还是将其作为脚本运行。

例如,Apache配置文件httpd.conf中的指令

AddType应用程序/ x-httpd-php .php

告诉服务器运行以.php结尾的文件以php脚本的形式运行。因此,只需确保没有保存任何以.php结尾,任何其他脚本可执行文件结尾或者用于包含文件的文件结尾的上载文件。

不要直接提供文件。将上传文件保存在没有公共访问权限的位置。从文件读取,输出缓冲区允许下载。

这是基本思想:

function ReadAndOutputFileChunked ($filename) { 
    $chunksize = 1*(1024*1024); // how many bytes per chunk 
    $buffer = ''; 
    $handle = @fopen($filename, 'rb'); 
    if ($handle === false) { 
        return false; 
    } 
    while (!feof($handle)) { 
        $buffer = @fread($handle, $chunksize); 
        print $buffer; 
    } 
    return @fclose($handle); 
}

header("Content-type: application/octet-stream");
ReadAndOutputFileChunked('/private/path/to/upload/files/' . $nameOfFile);