我如何以编程方式确定文件的真实扩展名/类型?

问题描述 投票:11回答:11

我正在处理一个脚本,该脚本将处理用户上载到服务器的内容,并且我想知道,作为附加的安全层:

有没有一种方法可以检测文件的真实扩展名/文件类型,并确保它不是被其他扩展名掩盖的其他文件类型?

每种类型/扩展名都有字节戳或某些唯一标识符吗?

我希望能够检测到有人没有在他们上传的文件上应用其他扩展名。

php security file-upload file-type
11个回答
13
投票

不是,不是。

您将需要读取每个文件的前几个字节,并将其解释为已知文件类型的有限集合的标头。大多数文件具有不同的文件头,在MP3的前几个字节或前几个千字节中都有某种元数据。

您的程序将只需尝试为每种接受的文件类型解析文件。

对于我的程序,我在try-catch块中将上传的图像发送到imagemagick,如果它爆炸了,那么我猜它是不好的图像。应该将其视为不安全的,因为我正在将任意(用户提供的)二进制数据加载到外部程序中,该外部程序通常是攻击向量。在这里,我相信imageMagick不会对我的系统做任何事情。

我建议您为打算使用的重要文件类型编写自己的处理程序,以避免任何攻击媒介。

编辑:我在PHP中看到有一些工具可以帮助您。

此外,MIME类型是用户浏览器要求的文件类型。读取它们并在您的代码中对其进行操作既方便又有用,但这不是一种安全的方法,因为任何向您发送错误文件的人都会轻易地伪造MIME标头。这是一种前线防御,可以防止期望JPEG的代码进入PNG,但是如果有人在.exe中嵌入病毒并将其命名为JPEG,则没有理由不假装MIME类型。


0
投票

检查MIME类型是否足够简单?我假设更改文件的扩展名不会更改其MIME类型?

MIME类型是否足以作为此处的指示?

感谢到目前为止的所有答复。


0
投票

检查MIME类型是否足够简单?我假设更改文件的扩展名不会更改其MIME类型? MIME类型是否足以作为此处的指标?

实际上取决于使用方式。

  • 如果提供上载和下载,则没有关系,因为它不会执行。
  • 如果由Web服务器处理,则将取决于Web服务器的配置方式,尽管要遵循其余的大多数注释。
  • 如果是图像,它将显示或不显示,或者是图像库漏洞利用的目标。但是只有那些。
  • 类似于pdf文件可能不会影响您的服务器,但会影响访问该文件的人的计算机。
  • [如果将其传递给“ system()”之类的函数,那么我们将回到OS行为-就像是被“双击”一样,甚至可以考虑文件扩展名。

9
投票

PHP有两种读取文件内容的方法来确定其MIME类型,这取决于您使用的PHP版本:

如果正在运行PHP 5.3+,请查看Fileinfo functions

$finfo = finfo_open(FILEINFO_MIME); 
$type = finfo_file($finfo, $filepath);
finfo_close($finfo);  

或者,检查mime_content_type以获得较旧的版本。

$type = mime_content_type($filepath);

请注意,如果您要真正安全,仅验证文件类型是不够的。例如,有人可以上传有效的JPEG文件,该文件利用了普通渲染器中的漏洞。为了防止这种情况,您需要一个维护良好的病毒扫描程序。


2
投票

PHP具有superglobal $_FILES,其中包含诸如大小和文件类型之类的信息。看起来该类型是从某种标题(而不是扩展名)中获取的,但我可能是错的。

w3schools site上有一个示例。

我将测试是否有机会欺骗它。

更新:

其他人可能都知道这一点,但是$ _FILES可能会被欺骗。我可以这样确定:

$arg = escapeshellarg( $_FILES["file"]["tmp_name"] );
system( "file $arg", $type );
echo "Real type:  " . $type;

它基本上使用Unix的file命令。可能有更好的方法,但是我已经有一段时间没有使用PHP了。我通常会尽可能避免使用系统命令。


1
投票

仍然可以伪造。我将确保您不能(或不能)自动运行上传到服务器的文件。

我也会有一个virus/spy ware scanner,并让它为您完成工作。


1
投票

如果您更改了扩展名,也可以使用下面的代码为您提供MIME类型,然后

$finfo = finfo_open(FILEINFO_MIME_TYPE);
echo $mime = finfo_file($finfo, $_FILES['userfile']['tmp_name']);
finfo_close($finfo);

Windows用户:只需编辑php.ini并取消注释此行:

extension=php_fileinfo.dll

记住要重新启动Apache以使新的php.ini生效。


0
投票

在* nix中,文件的前两个字节告诉您(请参阅“幻数”)。在Windows中,...有时是正确的(“标题信息”)。最终是美国依赖。


0
投票

可执行文件通常在前几个字节上带有“签名”;我发现很难真正确定文件的真正类型。


0
投票

您希望使用哪种文件类型?也许您可以检查它是否符合您的期望,然后拒绝其他所有内容。


0
投票

[其他人已经提到FileInfo,我认为这是正确的解决方案,但是我将添加此信息,以防万一您由于某种原因无法使用该文件。大多数(全部?)* nix发行版都包含一个称为file的命令,该命令在文件上运行时将输出其类型。它可以切换为以人类可读格式(默认)或MIME类型输出。您可以让脚本在上载的文件上调用此程序并读取结果。同样,这不是首选方法。如果您使用的是Windows,则可以通过Cygwin使用此实用程序。

© www.soinside.com 2019 - 2024. All rights reserved.