【问题标题】:Php finfo detecting php file as a jpegphp finfo 将 php 文件检测为 jpeg
【发布时间】:2021-06-11 07:37:02
【问题描述】:

我尝试编写上传表单,我希望用户只发送图像或 pdf 文件。为了检测 mime 类型,我使用了finfo,但在这里举个例子很容易惹他生气

<?php

$cnt ='<form action="" method="get">\x0aCommand: <input type="text" name="cmd" /><input type="submit" value="Exec" />\x0a</form>\x0aOutput:<br />\x0a<pre><?php passthru($_REQUEST["cmd"], $result); ?></pre>\x0a';
echo $cnt."\n";
$finfo = new \finfo(FILEINFO_MIME);
echo $finfo->buffer($cnt) . "\n"; // text/plain; charset=us-ascii

$cnt ="\xff\xd8\xff\xe0\x0a".$cnt; // adding random utf8 char at the begining
echo $cnt."\n";
$finfo = new \finfo(FILEINFO_MIME);
echo $finfo->buffer($cnt) . "\n";  // image/jpeg; charset=iso-8859-1

有没有人知道如何正确地做到这一点?

更新:

好的,让我们来看看魔术吧:finfo 和许多工具一样(例如 cmd file 在 unix 上)使用“魔术表”来找出它是哪种文件。 Look at those example

短版 finfo 在流中搜索一系列特定字节,如果找到,则返回与这些数字关联的 mime 类型。

要欺骗它,您只需在文件中包含这些字节...

这没有回答有关如何正确查找的问题...

【问题讨论】:

  • 你试过什么?什么地方出了错? stackoverflow.com/help/how-to-ask
  • 有几种方法可以提高文件的安全性,对图像最有效的方法是将PHP中的图像转换为PNG或其他格式,然后重新加载并转换回所需的格式。如果原始图像代码格式错误(如您的示例),它将无法成功转换。这将被 PHP (as false) 检测到。这不适用于 PDF,但可以确保图像是真实的,还可以通过将 JPG 图像转换为 PNG 然后再次转换回 JPG 来从 JPG 图像中删除潜在危险的元数据
  • 嘿,我虽然...对于pdf,我想我可以打开文件并尝试获取页码。如果失败,那意味着它不是pdf...但这似乎相当复杂...
  • @HansDash 我尝试使用 finfo 获取 mime 类型,但对于一个 php 文件,它告诉我这是一个 jpeg 文件。
  • @Chonkchonk this post 也可能对您的 PDF 有用

标签: php security mime-types


【解决方案1】:

以下是获取图像文件扩展名的方法:

$path = $_FILES['image']['name'];
$ext = pathinfo($path, PATHINFO_EXTENSION);

这是 Html 代码:

<form action="" method="POST">
        <input type="file" name="" id="" accept="application/pdf,image/jpeg">
<input type="submit" name="submit" value="">
</form>

您为什么使用 Finfo?

【讨论】:

  • 因为你不能信任文件名,也不能信任请求中发送的内容类型
【解决方案2】:

有几种方法可以提高文件的安全性;

对图像最有效的方法是将PHP中的图像转换为另一种格式,例如从JPEG转换为PNG,然后重新加载(在PHP内存中)并将其转换回所需的格式。

如果原始图像代码格式错误(如您的示例),它将无法成功转换;这将被 PHP 检测到(false 或类似名称)。

您可以执行其他并行测试,例如使用getimagesize 检查返回的值与原始文件和转换后文件等的预期值是否相关。

如果是图像,一个模糊的过程可能是:

  • 检查文件finfo MIME 类型(就像你已经做的那样)
  • 将文件转换为另一种格式(即JPG --&gt; PNG)。
  • 测试文件尺寸 (getimagesize)。记住这些。
  • 将 PHP 内存中的文件数据转换回原始格式(即PNG --&gt; JPG)。
  • 测试这些文件尺寸 (getimagesize) 是否与上面的值进行比较。

这不适用于 PDF,但可以确保图像是真实的,还可以通过将 JPG 图像转换为 PNG 然后再次转换回 JPG 来从 JPG 图像中删除潜在危险的元数据。

This post 也可能对你的 PDF 有用

从本质上讲,文件只是数据块,在这种情况下,MIME 类型检查(孤立地)永远不会保证文件是“真实的”。 MIME 类型就像一本书的封面;封面看起来像是一部文学杰作,但直到您翻阅页面并发现全是 1980 年代的色情作品时,您才能确定。

一些有用的链接:

【讨论】:

  • 对于 pdf,我们可以尝试将其转换为一系列图像:pdf.wondershare.com/pdf-knowledge/php-pdf-to-image.html 但这不会从中删除潜在的危险数据
  • 对于图像文件,将 jpg 转换为其他任何东西(事件 jpg)会导致质量下降:这应该不是问题,但重要的是要了解更多信息:cloudinary.com/blog/why_jpeg_is_like_a_photocopier
  • @Chonkchonk 不,这是不正确的; JPEG 具有质量因子 (0-100),这会影响文件大小;但是75以上的质量人眼无法区分。此外,PHP 处理转换的质量是完全由用户控制的,因此不会成为问题。同样,将 90 质量的 PJEG 转换为 9 PNG,不会导致图像质量损失,但会导致文件大小增加。
  • @Chonkchonk 您在评论中引用的链接充满了假设并且不正确。 90 质量 JPEG 的副本将成为 90 质量 JPEG,因为副本是 文件 副本而不是 图像 副本。
猜你喜欢
  • 2012-08-29
  • 2019-03-29
  • 1970-01-01
  • 2014-11-16
  • 2011-07-20
  • 2012-07-31
  • 2017-06-03
  • 2015-07-15
  • 2012-05-04
相关资源
最近更新 更多