使用 imagecreatefrom* php 重新创建上传/链接的图像

信息安全 php 上传文件
2021-09-08 02:01:30

正如我在 StackOverflow 问题中所建议的那样,我现在将其指向信息安全组,因为尽管获得了多次支持,但没有人能够回答我的问题。

用户上传的图片占我正在开发的网站上的大部分内容。出于安全原因,我尝试将它们存储在 webroot 之外并使用它们来获取它们readfile(),但它太慢了,所以我不得不回到旧方法。

现在我希望确保所有上传的内容都经过 100% 清理,因为它们将存储在 webroot 中。我的问题是,如果用户将有害脚本重命名为 .jpg、.gif、.png 或 .bmp 并上传,如果使用这样的函数重新创建图像,执行或获取时它是否仍然有害:

function imageCreateFromAny($filepath) { 
    $type = exif_imagetype($filepath); // [] if you don't have exif you could use getImageSize() 
    $allowedTypes = array( 
        1,  // [] gif 
        2,  // [] jpg 
        3,  // [] png 
        6   // [] bmp 
    ); 
    if (!in_array($type, $allowedTypes)) { 
        return false; 
    } 
    switch ($type) { 
        case 1 : 
            $im = imageCreateFromGif($filepath); 
        break; 
        case 2 : 
            $im = imageCreateFromJpeg($filepath); 
        break; 
        case 3 : 
            $im = imageCreateFromPng($filepath); 
        break; 
        case 6 : 
            $im = imageCreateFromBmp($filepath); 
        break; 
    }    
    return $im;  
} 

换句话说,是否有办法欺骗其中一个imagecreatefrom*功能以脚本而不是图像的形式执行内容,或者甚至将通过此运行的有害脚本减少为损坏的图像?

更新 我还将检查文件类型和扩展名,但我想知道用户是否设法绕过这些,这最后的手段是否有助于以任何方式保护我的服务器和/或客户端。谢谢你。

3个回答

甚至通过此运行的有害脚本是否会被简化为损坏的图像?

不,图像中的任何有害代码仍然存在。

但它是否安全真的取决于你对imageCreateFromAny.

就其本身而言,imageCreateFromX不会对图像做任何事情。它不会重新创建它,它只是创建一个图像资源标识符,因此如果您愿意,您可以进一步更改图像。但是图像中的任何有害代码都会被保留。

您的exif_imagetype检查很容易被绕过,因此它不能确保图像不包含有害代码。

因此,如果您不检查文件扩展名,并且使用您的功能,例如:imagepng(imageCreateFromAny($imageName), $imageName);,那么这将是不安全的。

有没有办法欺骗其中一个imagecreatefrom*函数将内容作为脚本执行

希望不要。这不是您的代码中的漏洞,而是 PHP 本身的漏洞。

那么解决方案是什么呢?如何确保上传的图片不包含任何有害代码?想到两个想法:

  • 正如@Steffen Ullrich所说,您可以将图像转换为不同的格式,这肯定会破坏任何有害内容
  • 您可以在文件本身内部搜索有害内容应该可以通过排除 , 和 (不区分大小写)以这种方式排除包含 PHP 代码<?<%图像<script

这种方法只是减少了图像数据与正在处理它的 PHP 交互的程度——但文件与 readfile() 具有更大攻击面的东西交互。

同样验证内容对您的网络服务器是安全的,并不意味着它对客户端是安全的。

将它们存储在 webroot 中确实会带来额外的风险 - PHP 的运行时会很乐意搜索发送给它的任何文件以查找 PHP 代码,然后执行它。您在此处添加的代码不会阻止这种情况。PHP 代码通过 2 条路由进入 PHP 运行时 - 或者由网络服务器映射(通常基于 URL 的存在,该 URL 解析为以“.php”结尾的文件名)或通过 include/require/eval/create_function 等在您的PHP 代码。

您可以通过以下方式添加针对第一种方法的保护层

  • 不允许上传的文件具有 .php 扩展名
  • 限制上传到指定的目录树,其中 PHP 切换在 web 服务器中被禁用
  • 将内容上传到完全没有 PHP 的单独网络服务器的文档根目录

第二种方法的防御层有点棘手和昂贵——代码审计、suexec、禁用一些 php 函数、锁定你的操作码缓存。

一个有用的工具是转换文件,您已经在代码中完成了一半的工作,并且为客户端提供保护;如果它是 BMP 或 GIF 转换为 PNG。对于 JPeg,请使用 webp(如果您的用户可以忍受的话)等。虽然这不会完全防弹,但它对于消除攻击还有很长的路要走。

您向我们展示的代码仅读取内容并检查它是有效的图像格式。恶意软件,包括用 PHP 编写的恶意软件,可以嵌入任何这些文件格式中。除了检查文件格式是否正常之外,您的代码不会决定是否接受内容,也不会以任何方式显示正在修改的内容。

就目前而言,它并没有增加很多价值。

我认为无论如何都不会通过您的图像执行脚本,但请记住,每天都会发现恶意软件和新技术攻击,然后您必须实施不同级别的防御。我向您推荐以下内容:

  1. 实施验证:设置大小限制、文件名格式和扩展类型。验证非常重要,因为它是第一个攻击点,例如空注入攻击,有人可以创建一个名为“script.sh%00img.bmp”的文件,它可以在您的服务器上执行。记住验证必须在侧服务器上。
  2. 实施反自动化机制,例如验证码。您可以使用这种安全机制降低拒绝服务攻击的风险。
  3. 强化网络服务器:为您的文件设置一个隔离目录,设置正确的权限,例如,不要为您的文件设置执行权限,自定义错误消息和错误页面以及出现错误时的操作等其他设置。

我希望这些信息对您有所帮助。

祝你好运。