如何检查上传的文件是否是没有mime类型的图像?

Cli*_*ote 27 php upload file-upload image-processing mime-types

我想检查上传的文件是图像文件(例如png,jpg,jpeg,gif,bmp)还是其他文件.问题是我正在使用Uploadify上传文件,这些文件会更改mime类型并提供"text/octal"或类似mime类型的内容,无论您上传哪种文件类型.

除了使用PHP检查文件扩展名之外,有没有办法检查上传的文件是否是图像?

Ala*_*blo 39

我对这个主题的想法很简单:所有上传的图像都是邪恶的.

而且不仅因为它们可能包含恶意代码,而且特别是因为元标记.我知道浏览网页的抓取工具使用隐藏的元标记找到一些受保护的图像,然后播放他们的版权.也许有点偏执,但由于用户上传的图像不受版权问题的控制,我将其考虑在内.

为了摆脱这些问题,我使用gd系统地将所有上传的图像转换为png.这有很多优点:图像从最终的恶意代码和元标记清晰,我只有一种格式的所有上传的图像,我可以调整图像大小以符合我的标准,并... 我立即知道图像是否有效!如果无法打开图像进行转换(使用不关心图像格式的imagecreatefromstring),则认为图像无效.

一个简单的实现可能如下所示:

function imageUploaded($source, $target)
{
   // check for image size (see @DaveRandom's comment)
   $size = getimagesize($source);
   if ($size === false) {
      throw new Exception("{$source}: Invalid image.");
   }
   if ($size[0] > 2000 || $size[1] > 2000) {
      throw new Exception("{$source}: Too large.");
   }

   // loads it and convert it to png
   $sourceImg = @imagecreatefromstring(@file_get_contents($source));
   if ($sourceImg === false) {
      throw new Exception("{$source}: Invalid image.");
   }
   $width = imagesx($sourceImg);
   $height = imagesy($sourceImg);
   $targetImg = imagecreatetruecolor($width, $height);
   imagecopy($targetImg, $sourceImg, 0, 0, 0, 0, $width, $height);
   imagedestroy($sourceImg);
   imagepng($targetImg, $target);
   imagedestroy($targetImg);
}
Run Code Online (Sandbox Code Playgroud)

测试它:

header('Content-type: image/png');
imageUploaded('http://www.dogsdata.com/wp-content/uploads/2012/03/Companion-Yellow-dog.jpg', 'php://output');
Run Code Online (Sandbox Code Playgroud)

这并没有完全回答你的问题,因为这是与被接受的答案相同的黑客攻击,但我告诉你我使用它的理由,至少:-)

  • 直接在任意数据上使用`imagecreatefromstring()`也是危险的,因为DoS式攻击仍然可以用少量请求填充服务器的内存.不是从任意数据字符串中跳过创建整个图像资源(每个像素4个字节,RGBa位图),而应该首先使用接受答案中提到的`getimagesize()`来确保图像在可读格式,尺寸合理. (4认同)

Sco*_*son 33

您可以使用getimagesize()哪个在非图像上返回零的大小.

  • 据我所知,这实际上是完成这项工作所接受的黑客攻击.如果它们存在,我会有兴趣听到更好的方法. (2认同)
  • `exif_imagetype()`显然要快得多. (2认同)

rco*_*ode 5

您可以通过检查文件开头的幻数来验证图像类型.

例如:每个JPEG文件都以"FF D8 FF E0"块开头.

这里有关于魔术数字的更多信息

  • 不安全的imo,攻击者可以"FF D8 FF E0"的第一个字节,然后添加一些可能被执行的PHP代码 (6认同)
  • 重申,没有什么是安全的,PHP代码也可以通过使用JPG元数据部分注入到有效的JPG文件中. (2认同)

Jen*_*och 5

如果Uploadify真的改变了mime类型 - 我认为它是一个bug.它根本没有意义,因为它阻止开发人员在PHP中使用基于mime类型的函数:

这是一个小辅助函数,它根据文件的前6个字节返回mime类型.

/**
 * Returns the image mime-type based on the first 6 bytes of a file
 * It defaults to "application/octet-stream".
 * It returns false, if problem with file or empty file.
 *
 * @param string $file 
 * @return string Mime-Type
 */
function isImage($file)
{
    $fh = fopen($file,'rb');
    if ($fh) { 
        $bytes = fread($fh, 6); // read 6 bytes
        fclose($fh);            // close file

        if ($bytes === false) { // bytes there?
            return false;
        }

        // ok, bytes there, lets compare....

        if (substr($bytes,0,3) == "\xff\xd8\xff") { 
            return 'image/jpeg';
        }
        if ($bytes == "\x89PNG\x0d\x0a") { 
            return 'image/png';
        }
        if ($bytes == "GIF87a" or $bytes == "GIF89a") { 
            return 'image/gif';
        }

        return 'application/octet-stream';
    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)