我正在编写一个脚本,该脚本将处理用户上传到服务器的内容,作为附加的安全层,我想知道:
有没有办法检测文件的真实扩展名/文件类型,并确保它不是用不同扩展名屏蔽的另一种文件类型?
每种类型/扩展是否有字节标记或某些唯一标识符?
我希望能够检测到有人没有对他们上传的文件应用不同的扩展名。
我正在编写一个脚本,该脚本将处理用户上传到服务器的内容,作为附加的安全层,我想知道:
有没有办法检测文件的真实扩展名/文件类型,并确保它不是用不同扩展名屏蔽的另一种文件类型?
每种类型/扩展是否有字节标记或某些唯一标识符?
我希望能够检测到有人没有对他们上传的文件应用不同的扩展名。
不是真的,不。
您将需要读取每个文件的前几个字节,并将其解释为有限已知文件类型集的标头。大多数文件都有不同的文件头,在 MP3 的前几个字节或前几千字节中有某种元数据。
您的程序将不得不简单地尝试为您接受的每个文件类型解析文件。
对于我的程序,我在 try-catch 块中将上传的图像发送到 imagemagick,如果它爆炸了,那么我猜这是一个坏图像。这应该被认为是不安全的,因为我将任意(用户提供的)二进制数据加载到外部程序中,这通常是一个攻击向量。在这里,我相信 imageMagick 不会对我的系统做任何事情。
我建议为您打算使用的重要文件类型编写自己的处理程序,以避免任何攻击媒介。
编辑:我在 PHP 中看到有一些工具可以为您执行此操作。
此外,MIME 类型是用户浏览器声明文件的类型。阅读这些内容并在您的代码中对其进行操作非常方便且有用,但这不是一种安全的方法,因为任何向您发送错误文件的人都会很容易伪造 MIME 标头。这是一种前线防御,以防止期望 JPEG 的代码与 PNG 相冲突,但如果有人在 .exe 中嵌入病毒并将其命名为 JPEG,则没有理由不欺骗 MIME 类型。
PHP 有几种读取文件内容的方法来确定其 MIME 类型,具体取决于您使用的 PHP 版本:
如果您正在运行 PHP 5.3+,请查看Fileinfo 函数
$finfo = finfo_open(FILEINFO_MIME);
$type = finfo_file($finfo, $filepath);
finfo_close($finfo);
或者,查看 旧版本的mime_content_type。
$type = mime_content_type($filepath);
请注意,如果您想要真正安全,仅验证文件类型是不够的。例如,有人可以上传一个有效的 JPEG 文件,该文件利用了普通渲染器中的漏洞。为了防止这种情况,您需要一个维护良好的病毒扫描程序。
PHP 有一个超全局的 $_FILES来保存大小和文件类型等信息。看起来该类型是从某种标题中获取的,而不是扩展名,但我可能错了。
w3schools 网站上有一个例子。
当我有机会时,我将测试它是否可以被欺骗。
更新:
其他人可能都知道这一点,但 $_FILES 可以被欺骗。我能够以这种方式确定它:
$arg = escapeshellarg( $_FILES["file"]["tmp_name"] );
system( "file $arg", $type );
echo "Real type: " . $type;
它基本上使用Unix的文件命令。可能有更好的方法,但我有一段时间没有使用 PHP。如果可能,我通常会避免使用系统命令。
那仍然可以伪造。我会确保您不能(或不)运行自动上传到服务器的文件。
我也会有一个病毒/间谍软件扫描器,让它为你工作。
如果您更改了扩展名,您可以使用下面的代码为您提供 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 生效。
在 *nix 中,文件的前两个字节告诉你(参见“幻数”)。在 Windows 中,……有时这是真的(“标题信息”)。它最终取决于操作系统。
可执行文件通常在第一个字节上有一个“签名”;我发现很难真正确定文件类型到底是什么。
您期望什么文件类型?也许您可以检查它是否符合您的期望并拒绝其他所有内容。
其他人已经提到了 FileInfo,我认为这是正确的解决方案,但我会添加它以防万一您由于某种原因无法使用该解决方案。大多数(全部?)*nix 发行版都包含一个命令file
,当在文件上运行时将输出其类型。它具有以人类可读格式(默认)或 MIME 类型输出的开关。您可以让您的脚本在上传的文件上调用该程序并读取结果。同样,这不是首选方法。如果您使用的是 Windows,则可以通过 Cygwin 使用此实用程序。
检查 MIME 类型是否足够简单?我假设更改文件的扩展名不会改变它的 MIME 类型?
MIME 类型是一个足够强大的指标吗?
感谢您迄今为止的所有回复。
检查 MIME 类型是否足够简单?我假设更改文件的扩展名不会改变它的 MIME 类型?MIME 类型是一个足够强大的指标吗?
这实际上取决于它的使用方式。