我试图编写一个上传表单,我希望用户只发送图像或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 ="xffxd8xffxe0x0a".$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
和许多工具一样(例如unix上的cmdfile
(使用";魔术桌";看看的例子
短版本finfo
搜索流中的一系列特定字节,如果找到了,则返回与这些数字相关的mime类型。
要欺骗它,你只需要在你的文件中有这些字节。。。
这并不能回答如何正确发现的问题。。。
有几种方法可以提高文件安全性;
对于图像来说,最有效的方法是将PHP中的图像转换为另一种格式,例如从JPEG到PNG,然后重新加载(在PHP内存中(并将其转换回所需的格式。
如果原始图像代码格式不正确(例如(,它将无法成功转换;这将由PHP检测到(作为false
或类似的(。
您还可以进行其他并行测试,例如使用getimagesize
检查返回的值与原始文件和转换文件等中的预期值的相关性。
如果是一张图像,一个模糊的过程可能是:
- 检查文件
finfo
MIME类型(正如您已经做的那样( - 将文件转换为其他格式(即
JPG --> PNG
( - 测试文件维度(
getimagesize
(。记住这些 - 将PHP内存中的文件数据转换回原始格式(即
PNG --> JPG
( - 测试这些文件维度(
getimagesize
(是否与上面的值相比较
这不适用于PDF,但可以确保图像是真实的,还可以通过将图像转换为PNG,然后再次转换回JPG,从JPG图像中删除潜在的危险元数据。
这篇文章也可能对你的PDF 有用
从本质上讲,文件只是数据块,在这种程度上,MIME类型检查(孤立地(永远不会是保证文件"是"的可靠方法;真正的";。MIME类型就像一本书的封面;封面看起来像是一部文学杰作,但除非你翻阅页面,发现里面都是20世纪80年代的色情作品,否则你不会确定。
一些有用的链接:
- http://www.php.net/manual/en/function.exif-imagetype.php
- https://stackoverflow.com/a/11039258/3536236
- PHP检查文件是否为图像
以下是如何获取图像的文件扩展名:
$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?