【问题标题】:PHP image upload security approachPHP图片上传安全方法
【发布时间】:2011-09-06 08:36:59
【问题描述】:

我开发了一个 php 脚本来替换当前的脚本,这将对不同的市场/国家有很大的影响。 其他脚本之间的这个脚本提供了照片上传功能。

在阅读了大量有关该问题的信息后,我采用了下面描述的方法。 我非常感谢您的 cmets 的安全性。

  1. 照片已上传到 Web 根目录外的私人 777 文件夹中。
  2. 已执行白名单扩展检查(仅允许 jpg、gif、png),其他所有内容都将被删除。
  3. 使用 getimagesize 检查最小-最大尺寸和照片有效性。
  4. 检查 mimetype 和文件扩展名匹配。
  5. 将上传的照片调整为标准尺寸(使用 imagecopyresampled)。
  6. 将创建的文件另存为 jpg。
  7. 删除原始文件。
  8. 使用新的(非随机名称)保存照片,即 img51244.jpg。
  9. 根据不可预测的算法将新照片移动到公用文件夹的可变子目录(777 权限)。即,img10000.jpg 将存储在 photos/a/f/0/img10000.jpg,而 img10001.jpg 将存储在 photos/0/9/3/img10001.jpg。这样做是出于其他原因(将子域用于静态内容服务或使用 CDN)。

脚本将在 linux 专用服务器上运行。

【问题讨论】:

  • 这里什么都没有。除了文件夹的 777 权限外 - 据我了解,如果它具有 777 权限,则它不是私有的。但据我所知,这只有在您的服务器被入侵时才真正重要(至少通过这个脚本我看起来不太可能)
  • 777 听起来并不安全。可能与stackoverflow.com/questions/3644138/…有关
  • 对我来说听起来很不错,除了可能非常宽松的权限。也许他们可以有所限制?否则,这会做我能想到的一切,包括删除 EXIF 数据
  • 我将上传文件夹称为“私有”,与公共相反(在网络根文件夹下)

标签: php security file-upload


【解决方案1】:
  1. 根据定义,chmod 0777 的目录对登录到您服务器的其他用户是公共的,而不是私有的。正确的权限应该是 700 并且归 apache(或您的网络服务器运行的任何用户)所有。我不知道你为什么不在这里使用 php 的默认临时目录,因为它往往也在 web 根目录之外。
  2. 白名单是个好主意。小心有一个正确的实施。例如,正则表达式 /.png/ 实际上匹配 apng.php
  3. 这一步是个好主意。它基本上是检查文件魔法。
  4. 不是绝对必要的。在前面的两个步骤中,我们已经确定扩展名和文件格式是正确的。如果您需要客户端指定正确的 MIME 类型,您还应该检查给定的 MIME 类型和上面确定的类型是否等效。

步骤 5 到 8 与安全无关。

第 9 步:我假设您的网站允许所有人查看每张照片。如果不是这种情况,您应该有一个具有更长 URL 的 URL 方案(例如,图像的哈希值)。

【讨论】:

  • (-1) 777 并不意味着在通过网络可访问性方面是公开的——这就是他所说的。而且您的正则表达式示例暗示无论如何这都很重要... BTW exe是Windows扩展... :-/
  • @Raffael1984 我认为 phihag 知道这一点。就同一网络服务器上其他用户的可访问性而言,它仍然是公开的,这一个问题。但我同意如果您正确执行 3) 步骤 2) 是不必要的
  • @Raffael1984 是的。我不确定为什么这一步是必要的。更新了答案。
  • @Raffael1984 将示例中的结尾更新为.php,尽管这只是一个不应漏掉的示例。再次更新答案以明确 HTTP 可用性和系统范围的公共目录。
  • @Rook image 不是文件,而是目录。因此,+x 是允许用户traverse subdirectories 所必需的。
【解决方案2】:

您还应该检查上传的文件大小,因为 getimagesize 有时会超出可用 RAM 内存。假设您的脚本可能在任何时候崩溃(例如断电时)也很好,因此您应该实施一些清理程序以删除剩余的不需要的文件。

【讨论】:

  • php.ini 中已经限制了最大可上传文件大小。
  • 是的,但这并不意味着它足以避免超出 RAM 限制。
  • 如果它超过了 php.ini 中的大小,您将无法在 $_FILES 中获得文件名 - 所以您无法检查它的大小。
  • 还存在最小和最大文件大小检查。还有一个检查 php post_max_size ini set
  • @Maerlyn:是的,天才,不会。但是如果 php.ini 中的限制设置为 128mb 并且 32mb 足以使脚本崩溃呢?
【解决方案3】:

这是一个相当完整的方法,但我没有看到任何代码执行预防机制。

您应该确保图像的内容永远不会被包含(通过 include 或 require 调用)或通过 eval() 执行。

否则,文件末尾的php代码可能会被执行。

您也可以尝试检测图像内容中的 php 代码(例如使用 file_get_contents,然后使用正则表达式搜索“

【讨论】:

  • 除非您的服务器配置错误,否则我看不到 PHP 代码将如何在 JPG 文件中执行?
  • 这没有意义,因为很明显没有人会调用 eval 或包含在图像上。我想不出有人会想到这样做的任何场景(除非他刚开始使用 PHP)。
  • 一旦出现重新采样的照片,原始文件就会被删除。它仅按以下顺序与以下 php 函数一起使用:move_uploaded_file、filesize、getimagesize、imagecreatefromjpeg、imagecopyresampled。
  • @Sebastian Nowak:你不能假设开发人员不会犯错。已知对广泛传播的系统(例如 phpBB)通过图像上传(在他们的案例中为头像)进行代码注入的攻击。说没有人永远不会再犯这个错误只会导致这个缺陷被遗忘,直到有人再次使用它。我发现这篇文章有一些有趣的方法来利用这些漏洞(cmets 也很好,有一个空字符注入示例,用于将 .php ext 保留在文件名上):ha.ckers.org/blog/20070604/…
猜你喜欢
  • 2012-09-18
  • 2013-07-09
  • 1970-01-01
  • 2023-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-09
相关资源
最近更新 更多