【问题标题】:PHP file upload: mime or extension based verification?PHP文件上传:基于mime或扩展的验证?
【发布时间】:2011-11-13 01:12:00
【问题描述】:

当我尝试处理文件上传时,我应该根据文件 MIME 类型还是文件扩展名运行验证?

这两种文件验证方式的优缺点是什么?

还有,我还应该关注其他安全问题吗?

在这些日子里,我依赖 MIME 类型,但在这篇文章中获得最多投票的答案

File upload issues in PHP 说:

永远不要依赖浏览器提交的 MIME 类型!

【问题讨论】:

标签: php file-upload


【解决方案1】:

Mime-type 不是可靠的来源,因为它是从浏览器发送的(任何人都可以手动创建 HTTP 请求)。 PHP 不检查扩展名和矿山类型的等价性(http://ru.php.net/manual/en/features.file-upload.post-method.php)。您可以使用文件名“image.php”和 mime 类型“image/gif”来强调 HTTP 请求。

如果您想将上传的文件保存到 HDD 并在以后提供对该文件的公开访问权限,请始终使用扩展验证。

【讨论】:

  • 扩展是完全任意的,远不如浏览器 mime 类型可靠。如果您愿意质疑浏览器的 mime-type,那么您应该肯定质疑扩展:扩展来自用户!
  • Web 服务器(apache 等)检测如何按扩展名处理文件。如果您接受带有文件名“image.php”和 mime 类型“image/gif”的 HTTP 请求并保存到 HDD 文件“image.php”(扩展名为 .php)上的公共目录,apache 将像 php sсript 一样处理此文件(黑客可以上传这个文件,上传后请求它并获得对服务器的完全访问权限)。
  • @mkharitonov 你必须在你想说话的人前面添加一个@。然后他们会收到您的回复通知
【解决方案2】:

为了准确确定已上传的内容,您无需检查文件扩展名或 浏览器 发送的 mime 类型。

在 *nix 环境中,您拥有检查给定文件的 mime 类型的实用程序,通常位于 magic.mime 文件(/usr/share/magic.mime 或类似文件,取决于您的设置)。

从 magic.mime 中复制/粘贴,以便您简要了解它的工作原理:

# Magic data for KMimeMagic (originally for file(1) command)
#
# Note on adding additional MIME types:
#
# [RFC2045,RFC2046] specifies that Content Types, Content Subtypes, Character
# Sets, Access Types, and conversion values for MIME mail will be assigned and
# listed by the IANA.
# http://www.iana.org/assignments/media-types/
#
# Any unregistered file type should be listed with a preceding x-, as in
# application/x-foo (RFC2045 5.1), or a x., as in application/x.foo (RFC4288
# 4.3).  Any non x-prefixed type should be registered with IANA and listed at
# the above address.  Any other behavior is a MIME standards violation!
#
# It is preferred that when a registered MIME type exists, that
# the registered Content-Type and Subtype be used to refer to a file of
# that type, so don't use application/x-zip when application/zip is
# registered.
#
# If an active RFC suggests that a MIME registration for a new type is in
# progress, make a note of it pointing to that RFC.
#
# The format is 4-5 columns:
#    Column #1: byte number to begin checking from, ">" indicates continuation
#    Column #2: type of data to match
#    Column #3: contents of data to match
#    Column #4: MIME type of result
#    Column #5: MIME encoding of result (optional)

我将为您提供一个链接,该链接将帮助您在 PHP 中进一步实现(字面意思是 2 行代码,一旦您完成)。

如果您在所有这些之后仍无法使其正常工作,请在 cmets 中发布,我将提供安全检测已上传内容所需的完整代码。

Fileinfo

【讨论】:

  • 那么,如果我不使用这个魔法有什么问题呢?什么是攻击场景?
  • @Col。弹片 - 如果你不使用它,我没有说任何问题。我已经使用这种方法很长一段时间了,如果我更改文件扩展名,我从来没有遇到过接收错误 mime 类型的问题。如果有人想使用文件分机。 / browser 报告了 mime 类型检测 - 继续吧,最后真的不会打扰我:) 只是分享我的经验和使用的方法。
  • 你总是不回答我的问题。只有你能做的就是跑来跑去大喊“危险!!危险!!”,但不能解释你在说什么特别危险。
  • @Col。弹片 - 我们不是来回答你的问题的。此外,令我震惊的是,您对此过于个人化,对此相当粗暴,而且通常不是非常友好或专业。我什至不想发表这种评论,但你在这里的态度真的令人震惊。请后退一点。如果你是对的,请用客观事实来支持它,而不是左手侮辱和讽刺。很抱歉打扰其他人在这里的讨论,但我觉得有必要说出来。
  • @Chris We are not here to answer your questions. - 这很可悲,但确实如此。没有人愿意停下来思考。
【解决方案3】:

好的,所以对于这里的所有天才,我已经准备了一些教程:

  1. 下载这个pretty php logo I drew
  2. 查看。很不错,不是吗?
  3. 将其重命名为whatever_you_like.php
  4. 通过所有出色的 mime 类型/任何检查器进行检查
  5. 运行它

总之,你永远不应该永远依赖 MIME 类型。你的网络服务器不关心 MIME 类型,它决定了 EXTENSION 做什么,最终被否决的 @Col。弹片的回答其实是对的。检查 MIME 提供给您的任何信息在执行时绝对与您的网络服务器无关。

编辑:打开网站以应对此类攻击的不常见代码:

<?php

$mimetype = mime_content_type($_FILES['file']['tmp_name']);
if(in_array($mimetype, array('image/jpeg', 'image/gif', 'image/png'))) {
   move_uploaded_file($_FILES['file']['tmp_name'], '/whatever/something/imagedir/' . $_FILES['file']['name']);
   echo 'OK';

} else {
    echo 'Upload a real image, jerk!';
}

【讨论】:

  • 顺便说一句,我为这种傲慢的语气道歉,但这样的回答让我很反感。
  • @giga 谢谢。我希望这可以帮助某人意识到验证用户提供的文件时的实际问题。
  • 它作为“软件使用”字符串存储在EXIF data。顺便说一句,不要因为不知道这一点而感到羞耻。这就是为什么有像 SO 这样的网站,您可以在其中询问一些有能力的人。不幸的是,今天似乎没有很多。
  • 首先,没有必要如此公然无礼。听说过 ad hominem 吗?如果你是对的,那么你的答案应该是独立的,没有侮辱性的。其次,如果您只是要将上传的文件转储到服务器上的公用文件夹中,那么扩展检查是有意义的 - 为什么要将 php 文件作为图像?但是,如果您使用 GD 或其他一些图像函数来处理上传的图像,则 mime 类型更重要,因为非图像文件会破坏您的代码,并且不会保存上传的文件。检查两者是最安全的方法。
  • 感谢@jehy 让示例再次运行。但我不能真正画出这样的 PHP 徽标,原始图像包含类似... 7 秒的 mspaint 工作,其中 5 秒我正在休息:-)
【解决方案4】:

None 不适合准确找出文件的类型。原因是—— * 扩展 - 用户只需重命名文件即可轻松更改扩展。 * Mime 类型 - 要更改 mime 类型,一些附加组件/扩展可以做到这一点,因为它来自客户端(因此可以在发送到服务器之前更改),而不是由服务器生成。

现在进行验证,问题的答案取决于您为什么要验证文件类型。

大多数时候我们需要确保上传的文件不会被执行。出于这个原因,您需要确定您的服务器如何处理/执行文件。 - 如果您的服务器检查扩展名以进行验证,您还需要验证您没有存储可以执行的扩展名文件。 - 如果您的服务器使用 mime-types,请注意客户端发送的 mime-type 和服务器对同一文件使用的 mime-type 可能不同。因此,请使用与您的服务器相同的逻辑来找出 mime 类型。

【讨论】:

    猜你喜欢
    • 2014-11-06
    • 2015-10-18
    • 2011-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-28
    • 2012-01-02
    • 2021-03-09
    相关资源
    最近更新 更多