PHP上传文件增强安全性

Posted

技术标签:

【中文标题】PHP上传文件增强安全性【英文标题】:PHP Upload file enhance security 【发布时间】:2011-02-14 15:14:26 【问题描述】:

嘿.. 我的问题是如何防止有人上传病毒或一些带有你假装扩展名的恶意代码,例如我有一个 pdf 文件上传器,任何人都可以上传带有 pdf 伪装的二进制文件,有很多程序可以做到这一点.

【问题讨论】:

【参考方案1】:

看看 php 的 FileInfo 扩展。 实际内容类型的识别类似于unix file command。 但这仅对简单重命名的恶意用户有用,例如将virus.exe 转换为virus.pdf。它不会阻止有害 pdf 的上传(在一个或多个更广泛的 pdf 阅读器中使用一些错误)。

【讨论】:

【参考方案2】:

上传文件时会出现许多安全问题。第一个问题是该文件可能不是您想要的文件,在本例中为 pdf。变量$_FILES['file_name']['type'] 由攻击者控制,无法永远被信任。该值通常使用漏洞利用代码或使用篡改数据进行修改。

1) 安全系统的第一步是确保文件具有 .pdf 扩展名:

if("pdf"!=substr($fileName, strrpos($fileName, '.') + 1))
   die("Invalid File Type");

2)接下来您应该使用 php filetype() 函数检查它是什么文件类型。

3)一个严重的问题是这些PDF文件可以利用诸如buffer overflows之类的漏洞,这些漏洞在Adobe制作的软件中很常见。这些 PDF 用于在Drive By Download 攻击中传播病毒。

最好的解决方案是安装Web应用防火墙Mod_Security。这将阻止 sql 注入和 xss 等攻击攻击您的 Web 应用程序。 Mod_Secuirty 可以配置为使用modsec-clamscan 扫描所有上传文件中的病毒。

【讨论】:

Rook 感谢您的帖子,除了我将要求安装在我的 hostgator 主机上的 mod_security 之外,我已经涵盖了所有安全性。谢谢老兄:) filetype() 有什么帮助?在我看来,它所要做的就是告诉你文件是文件还是目录。也许你的意思是finfo-file()? @MichaelKopinsky:确实,这可能是一个错字。【参考方案3】:

您无法阻止某人上传病毒。最好的方法是对上传到您网站的所有文件运行像 clamscan 这样的病毒扫描。

使用扩展检查/MIME 检查只会告诉您文件名称正确,或者具有正确的 MIME 签名。在您实际扫描之前,您无法判断是否存在病毒。

【讨论】:

【参考方案4】:

我们使用fileinfo + 文件扩展名检查的组合。虽然浏览器通常会发送您不应该信任的 mime 类型,因为它可能会被劫持

在我们的例子中,我们不在我们的服务器中运行任何文件。所以我们要做的是有一个extension while list 像(例如):pdf jpg png 等等......和一个blacklisted mime extensions 的列表。这样我们就避免了文件的扩展名与 MIME 类型不匹配的风险。

一旦文件保存在服务器中,我们总是将 mime 类型强制为application/octet-stream,因此文件总是被下载。

类似这样的:

<?php

$allowed_types = array(
/* images extensions */
'jpeg', 'bmp', 'png', 'gif', 'tiff', 'jpg',
/* audio extensions */
'mp3', 'wav', 'midi', 'aac', 'ogg', 'wma', 'm4a', 'mid', 'orb', 'aif',
/* movie extensions */                              
'mov', 'flv', 'mpeg', 'mpg', 'mp4', 'avi', 'wmv', 'qt',
/* document extensions */                               
'txt', 'pdf', 'ppt', 'pps', 'xls', 'doc', 'xlsx', 'pptx', 'ppsx', 'docx'
                        );


$mime_type_black_list= array(
# html may contain cookie-stealing javascript and web bugs
'text/html', 'text/javascript', 'text/x-javascript',  'application/x-shellscript',
# PHP scripts may execute arbitrary code on the server
'application/x-php', 'text/x-php', 'text/x-php',
# Other types that may be interpreted by some servers
'text/x-python', 'text/x-perl', 'text/x-bash', 'text/x-sh', 'text/x-csh',
'text/x-c++', 'text/x-c',
# Windows metafile, client-side vulnerability on some systems
# 'application/x-msmetafile',
# A ZIP file may be a valid Java archive containing an applet which exploits the
# same-origin policy to steal cookies      
# 'application/zip',
                        );


$tmp_file_extension = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));

if(!strlen($tmp_file_extension) || (!$allow_all_types &&
  !in_array($tmp_file_extension,$allowed_types))) 
    return false;


$finfo = new finfo(FILEINFO_MIME, MIME_MAGIC_PATH);

if ($finfo) 
    $mime = $finfo->file($file_name_tmp);

else 
    $mime = $file_type;


$mime = explode(" ", $mime);
$mime = $mime[0];

if (substr($mime, -1, 1) == ";") 
    $mime = trim(substr($mime, 0, -1));


return (in_array($mime, $mime_type_black_list) == false);

除此之外,您还可以使用clamav + php extension 添加virus scan

【讨论】:

【参考方案5】:

allow users to securely upload files in PHP 最简单的两步回答是:

    始终将文件保存在文档根目录之外 编写一个 PHP 脚本来提供文件,但不允许它们被执行

这将阻止大多数基于文件上传的攻击,但不是全部。更彻底和完整的解决方案包括以下各项:

    永远不要将文件存储在文档根目录之外,通过代理脚本提供它(如上)。 使用finfo_file() 验证实际文件内容的MIME 类型。 上传时,保存为随机文件名而不是提供的文件名,并使用数据库行来保留元数据(这样您的代理脚本就可以找到正确的文件来提供服务)。 对磁盘上的实际文件内容进行编码/加密,并让您的脚本对其进行解码/解密。这可以防止恶意用户上传恶意负载,然后使用另一个漏洞(例如 LFI)来触发它。在这种情况下,base64_encode() 应该提供足够的保障。 (但如果您的应用程序中存在其他漏洞,您应该真的修复它。)

如果您执行上述所有操作,您的上传表单就不可能成为漏洞来源。

【讨论】:

这是我第一次读到关于您的第 4 点用于文件上传的信息。别的地方没见过。 +1.为什么这么多是用相互矛盾的观点写的,这里和 php.net 的爱......不要那样做。不要这样做。我喜欢你的帖子。

以上是关于PHP上传文件增强安全性的主要内容,如果未能解决你的问题,请参考以下文章

PHP图片上传安全检查清单

检查上传的文件是不是在 php 中属于不安全的文件类型

安全的 PHP 文件上传脚本

PHP文件上传失败移动文件

小迪安全 Web安全 基础入门 – 第十三天 – PHP开发 – 个人博客项目&文件操作类&编辑器&上传下载删除读写

文件上传漏洞与利用