【发布时间】:2009-11-02 19:28:04
【问题描述】:
我使用PHP语言进行文件上传,想知道我使用的以下方法是否安全?
我正在使用简单的方法进行文件上传, 我从 $_FILES['userfile']['type'] 检查文件名 然后如果它有一个允许的文件扩展名,我用一些随机数上传文件。 比如如果是 abc.zip 它可能会变成 8w43x9d.zip。
请告诉我:文件上传的方法真的很糟糕吗?
【问题讨论】:
标签: php
我使用PHP语言进行文件上传,想知道我使用的以下方法是否安全?
我正在使用简单的方法进行文件上传, 我从 $_FILES['userfile']['type'] 检查文件名 然后如果它有一个允许的文件扩展名,我用一些随机数上传文件。 比如如果是 abc.zip 它可能会变成 8w43x9d.zip。
请告诉我:文件上传的方法真的很糟糕吗?
【问题讨论】:
标签: php
随机生成的安全文件名绝对是一件好事。但是,如果您允许文件扩展名通过 webroot,您仍然需要确保扩展名不会在服务器上引起任何问题,例如 .php(好的,应该在 web 中禁用 PHP 处理服务器上传目录,但仍然)。如果您使用的是 Windows 服务器,也会出现问题,其中尾随的点和空格会混淆文件系统;确保将扩展锁定为一些“已知良好”的值。
不幸的是,['type'] 属性根本无法依赖。有些浏览器不会填写内容类型,有些浏览器会输入错误的类型,因为他们的操作系统设置不当(一个臭名昭著的无用的是 Windows 上的 IE 默认调用 JPEG image/pjpeg),有些人总是说 @987654324 @ 甚至是text/plain。
即使['name'] 属性也不可靠;除了浏览器撒谎或混淆值之外,给定类型总是有可能在该特定机器上具有意外的文件扩展名。或者,对于 Mac 和 Linux 客户端,上传的文件完全有可能根本没有扩展名(或者甚至可能对于操作系统认为的类型有错误的扩展名)。
所以是的,这有点乱。虽然从 Content-Type 提交或文件扩展名中嗅探类型对于猜测文件应该是什么默认类型很有用,但它完全不可靠,因此提供手动方法来选择文件类型是一件好事。或者,如果您将上传的文件作为附件提供(例如,通过 PHP 脚本设置 Content-Disposition: attachment),您通常只需调用所有内容 application/octet-stream 并让用户在保存时对其进行整理。
如果您不用作附件,则可能存在安全问题。 IE 会很高兴地嗅探您为<html> 标签提供的许多文件类型,并将这些文件视为 HTML,即使您告诉它它们是别的东西。然后它可以在浏览器中内联显示它们,并让它们将脚本注入到您的安全上下文中。如果您的安全上下文中有任何重要内容,例如用户帐户和 cookie,那么这就是跨站点脚本安全漏洞。解决方法是作为附件和/或从不在主站点安全上下文中的不同主机名提供服务(通常使用子域)。
允许您不完全信任的用户将文件上传到您的服务器实际上是一项比 PHP 教程中的琐碎示例代码让您相信的困难得多的任务。 :-(
【讨论】:
来自PHP Manual:
$_FILES['userfile']['type']
文件的 mime 类型(如果浏览器提供了此信息)。一个例子是“image/gif”。然而,这种 mime 类型在 PHP 端没有被检查,因此不要认为它的价值是理所当然的。
我不会相信用户或用户的浏览器发送给我的任何内容。
如果您想学习,我会看看现有的安全资源,例如 PEAR 的 HTTP_Upload。您甚至可以考虑使用 Beta 版。
【讨论】:
ca2. 前缀的情况下工作。链接没有损坏。它可能会在您的最后被阻止。
除了上面的帖子,我们还依赖FileInfo 或SplFileInfo,到目前为止,它已被证明是满足我们需求的最佳选择。
【讨论】: