如何验证上传的文件是否为视频


How do I validate that an uploaded file is a video?

我有一个服务器上有一些非常敏感的信息,所以安全性是一个大问题。用户需要能够上传视频。我知道允许用户上传文件会带来安全威胁,因为没有 100% 的方法可以阻止他们上传非视频。但我显然可以选择服务器将保留哪些文件。

我知道检查文件扩展名是不够的。检查MIME类型更好,但它仍然可以伪造。那么如何检查文件是否是视频呢?

玩吧!

确定的唯一方法是有一些代码来解码相关类型的视频,看看它(并检查是否有合理的结果,例如非零持续时间)。

否则,您的风险很低:

非恶意方案:

    上传
  1. 者上传的视频,内容类型为 video/* 内容。
  2. 存储八位字节和内容类型。
  3. 下载
  4. 器下载视频,您使用收到的内容类型。
  5. 下载器观看视频(或抱怨编解码器等)

恶意场景 1:

    上传
  1. 者上传了一个令人讨厌的木马,带有视频/* 内容类型。
  2. 存储八位字节和内容类型。
  3. 下载
  4. 器下载讨厌的特洛伊木马,您使用您收到的内容类型。
  5. 下载器在视频播放器中打开讨厌的木马。讨厌的木马什么都不做,因为它不是视频。用户抱怨编解码器。更糟糕的情况是,他们在 ubuntu 论坛上写下关于缺乏对专有格式的支持的咆哮,在您的页面上添加拼写错误的评论,说明该网站由于视频不起作用而如何糟糕,等等。

恶意场景 2:

    上传者上传令人讨厌的特洛伊木马,这些特洛伊木马被
  1. 写入视频中,该特洛伊木马利用流行的视频播放器存在某些缓冲区溢出问题。
  2. 你存储...
  3. 下载器...
  4. 可能只是上述之一,但也可能是他们受到漏洞攻击(如果他们正在使用受影响的播放器)。

不过,关于方案 2 需要注意的三件事:

  1. 测试它是视频并不能保证安全,因为它在某些播放器中也可以正常工作。
  2. 测试它是视频可能会使您的服务器容易受到攻击,如果漏洞在 ffmpeg 中!
  3. 这种类型的漏洞利用既罕见又很难做到。一般风险与上传和下载 jpeg 或 png 相同。事实上,它有点小(确实有一段时间影响常用 jpeg 库的这种类型的漏洞)。

总而言之,只要确保你只输出你接受的内容类型,并强制文件扩展名匹配它们;如果用户上传一个名为哈哈哈.exe的视频/MPEG,那么

重命名哈哈哈.mpg

编辑:哦,还有:

恶意场景 3:

上传

者上传的视频会以使用大量资源的方式利用某些播放器。在这种情况下,下载器只会kill-9/ctrl-alt-delete/your-OSs-kill-them-all-of-choice,但是如果您的服务器正在测试它是一个视频,那么它最终可能会遇到麻烦,因为没有人介入并杀死它试图解释的200个(并且随着脚本小子的脚本不断上传更多)"视频"。

仅仅进行正常的视频处理就足以引入DoS功能(毕竟视频处理相对较重),因此测试文件可能会带来比节省更多的危险。

您可以通过 php 扩展调用ffmpeg

https://github.com/char0n/ffmpeg-php/

它基本上包装了ffmpeg的输出,然后你可以在 PHP 中签入。但是,您应该首先熟悉ffmpeg,这本身就是一个完整的主题。如果你不想使用这个库,你可以通过exec自己执行ffmpeg。

此外,我会检查哑剧类型。您还可以通过 JS 在文件输入中检查客户端的文件(并非在所有浏览器中,这不能替代真正的验证)。

LG,

弗洛

用户可以安全地上传任何内容,只要它进入正确的目录并且服务器上没有任何内容试图运行它(如果它应该是视频,则不会尝试)。除非受害者以某种方式激活它,否则恶意软件无法做任何事情。

我同意,除非视频播放器存在可以通过某些损坏的视频文件利用的问题,否则我不会太担心。但是,假设不一定出于安全原因,必须检查您拥有的文件是否是视频文件并且所有文件都是有效的,您可以执行以下步骤

  1. 对文件运行 ffprobe 而不带参数。它将提供有关文件的一些信息。编解码器、容器、持续时间、帧速率、比特率。
  2. 现在使用 -show_packets 运行 ffprobe 。它应该逐帧提供有关文件的信息。您应该获得与第一个命令给出的持续时间*frame_rate一样多的视频帧。这可以检查,因为有人可以只提供精心制作的标题或文件的初始部分可能是有效的视频(ffmpeg 和 ffprobe 只会测试视频的前几秒钟以验证其类型),其余的可能已损坏。
  3. 使用 -show_frames 运行 ffprobe 。这将尝试解码每个帧的标头,以确保每个帧都是有效的视频帧。这是一个额外的步骤,因为某些容器只有一个可用于show_packets的表。因此,ffprobe 可能只是读取该表,它指向的数据可能已损坏。

现在理论上有可能一个文件具有每一帧的所有有效标头,但数据错误,但没有解码实际内容并在播放器上查看它,这是您可以做的最好的 afaik。我想说这已经足够好了,而且非常快。