【问题标题】:Secure User Image Upload Capabilities in PHPPHP 中的安全用户图像上传功能
【发布时间】:2010-09-04 21:55:03
【问题描述】:

我正在为我的网站实施基于用户的图片上传工具。系统应该只允许任何用户上传 JPEG 和 PNG 文件。当然,我担心安全问题,所以我想知道许多比我聪明的人对以下允许上传的检查有何看法:

1) 首先将 PHP 中允许的文件扩展名列入白名单,以仅允许 PNG、png、jpg、JPG 和 JPEG。通过如下函数检索用户文件的扩展名:

return end(explode(".", $filename));

这应该有助于禁止用户上传诸如 .png.php 之类的恶意内容。如果通过,请转到第 2 步。

2) 对 TMP 文件运行 php 函数 getimageize()。通过类似的方式:

getimagesize($_FILES['userfile']['tmp_name']);

如果这没有返回 false,请继续。

3) 确保将 .htaccess 文件放在上传目录中,这样该目录中的任何文件都无法解析 PHP 文件:

php_admin_value engine Off

4) 将用户的文件重命名为预先确定的名称。即。

$filename = 'some_pre_determined_unique_value' . $the_file_extension;

这也有助于防止 SQL 注入,因为文件名将是任何使用的查询中唯一由用户确定的变量。

如果我执行上述操作,我仍然容易受到攻击吗?在接受文件之前,我希望 1) 只允许 jpgs 和 pngs,2) 验证 PHP 说它是一个有效的图像,3) 禁用图像所在的目录执行 .php 文件和 4) 将用户文件重命名为独一无二。

谢谢,

【问题讨论】:

  • 你能在图像文件上使用 strip_tags 来删除 PHP 标签吗?

标签: php security image file-upload upload


【解决方案1】:

关于文件名,随机的名字绝对是个好主意,可以消除很多麻烦。

如果您想完全确保内容是干净的,请考虑使用 GD 或 ImageMagick 将传入的图像 1:1 复制到一个新的空图像中。

这会略微降低图像质量,因为内容会被压缩两次,但它会删除原始图像中存在的所有 EXIF 信息。用户通常甚至不知道有多少信息被放入 JPG 文件的元数据部分!相机信息、位置、时间、使用的软件...托管图像的网站为用户删除这些信息是一个很好的政策。

此外,复制图像可能会消除大多数利用错误图像数据导致查看器软件溢出并注入恶意代码的漏洞。 GD 可能无法读取这种经过处理的图像。

【讨论】:

  • 很好的答案。我将添加它作为额外的防御,提供来自您设置 cookie 的域以外的一次性域的图像。这样一来,即使图像以某种方式具有可执行的客户端代码,浏览器的同源策略也可以防止很多伤害。
  • @sri 好主意,没想到!
  • @SripathiKrishnan 如何为图像设置丢弃域..任何参考..供您回答
  • @sid - 购买另一个域并提供来自该域的图像。例如,谷歌提供来自域 googleusercontent.com 的用户内容。
  • @SripathiKrishnan 谢谢..我将如何确保域是无 cookie 的,上传照片时我是否必须将图像保存在该域中?
【解决方案2】:

关于您的数字 2),不要只检查 FALSE。 getimagesize 还将返回图像的 mime 类型。与查看客户端提供的 mime 类型相比,这是一种更安全的检查图像类型的方法:

$info = getimagesize($_FILES['userfile']['tmp_name']);
if ($info === FALSE) {
    die("Couldn't read image");
}
if (($info[2] !== IMAGETYPE_PNG) && ($info[2] !== IMAGETYPE_JPEG)) {
    die("Not a JPEG or PNG");
}

【讨论】:

  • 一个文件可能是有效的 gif 并同时包含 php 代码。因此 getimagesize() 不会提供太多真正的保护。
  • @Andre:任何可以包含文本的东西都可以包含 PHP 代码。至少对于图像,除非网络服务器的配置非常糟糕,否则 PHP 不会被执行。
  • 我通常使用 imagick 将图像重新编码为 bmp 并返回到原始扩展 - 这可以消除该图像文件中的任何恶意代码。
【解决方案3】:

所有检查似乎都不错,尤其是第 3 项。如果性能不是问题,或者您在后台执行此操作,您可以尝试使用 GD 访问图像并查看它是否确实是图像,而不仅仅是有人试图填充您的服务器的一堆废话。

【讨论】:

    【解决方案4】:

    关于第 2 条,我在 php.net (documentation of the function getimagesize()) 上看到:

    不要使用 getimagesize() 来检查给定文件是否为有效图像。请改用专门构建的解决方案,例如 Fileinfo 扩展。

    【讨论】:

      猜你喜欢
      • 2012-10-25
      • 2011-05-12
      • 1970-01-01
      • 1970-01-01
      • 2012-09-18
      • 1970-01-01
      • 2023-01-18
      • 2015-04-22
      • 2013-07-09
      相关资源
      最近更新 更多