【问题标题】:Best way to handle animated GIF with PHP用 PHP 处理动画 GIF 的最佳方法
【发布时间】:2021-04-28 14:39:22
【问题描述】:

首先,对不起我的语法不好。英语不是我的主要语言...

我正在开发一个完全 AJAX 的 wordpress 主题,其中包含前端线程提交表单,我想添加动画 GIF 支持。

我写了一段使用imagick库的PHP代码:

 // there is also another function that
 checks image's exif, size, width, height, finfo and retuns true if all good.


  // first imagick resize is basicly re-coding the image to kill shell/hack codes in the gif.
  $imagick =  new Imagick($image['tmp_name']);
  $imagick = $imagick->coalesceImages();

  foreach($imagick as $frame){
    $frame->scaleImage($width, 0);

  }

  $imagick = $imagick->deconstructImages();
  $imagick->writeImages($new_image_name, true);
  $imagick->destroy();

 // and this one for the thumbnail of the post.
 $imagick =  new Imagick($image['tmp_name']);

  $imagick = $imagick->coalesceImages();

  foreach($imagick as $frame){
  $frame->scaleImage(wp_get_registered_image_subsizes()["left-frame-thumbnail"]["width"], 0);
  }
    
      $imagick = $imagick->deconstructImages();
      $imagick->writeImages($new_image_name, true);
      $imagick->destroy();

代码就像魅力一样,但我注意到这是一个昂贵的代码。我的意思是如果用户上传一个大的 gif 文件,我认为它会导致 CPU 峰值。

如果我将 GIF 大小限制为 2MB 就没有关系,因为其他问题是帧数。我们知道,当我们调整 GIF 的大小时,我们会拆分所有帧,调整它们的大小并将它们重新连接在一起。有很多 300kb 左右的 gif,但其中包含 50 多个帧。所以帧数也是服务器CPU的问题。

然后我说;嘿!让我们用 Javascript 在客户端调整 gif 的大小!我写了一个在客户端调整 gif 大小的代码。这确实非常有效。

我在服务器端编写了一个代码来获取调整大小的 2 gif 文件并将它们直接保存到服务器(同时检查它们的 exif、尺寸、finfo)。很好,服务器 CPU 很好。

但是!我注意到第一条规则:“永远不要相信来自客户端的数据。”

如果我在客户端调整它的大小,那很好。调整大小会杀死图像中的 hack/shell 代码。但是,如果用户发送假的 2 两个看起来像是刚刚调整大小并通过控制台或其他方式来自表单的文件怎么办?

我的 ajax 提交中已经有一个 CSRF 令牌,但我确定这还不够。

总结:处理动画 GIF 的最佳方式是什么?我做错了什么。

【问题讨论】:

  • 在浏览器中调整动画 GIF 的大小时,您实际上做了什么? AFAIK,您只能调整此类图像的大小仅用于表示目的,实际图像未调整大小..? “在我看来它会导致 CPU 峰值”你真的检查过这个还是你认为它会?
  • 你好@Teemu!我混合了 2 个 github 项目来调整来自文件输入的 gif 大小。其中一个名为“gifFrames”(将帧拆分为画布),另一个名为 gifShot,可以从画布创建 gif。我无法理解你的第二个问题。我已经用它的宽度调整了实际/原始图像的大小,以针对其中的错误代码进行复制。我正在使用 ryzen 5 3600 CPU 在我的本地主机上制作这个 resize proc,当它调整包含 50+ 帧的 gif 大小时,它需要 4 秒并导致 php CPU 使用率在 %15-20 左右。我认为使用廉价主机的用户网站会死掉。
  • 如果我拆分工作怎么办?我可以将 gif 拆分为帧并在浏览器上调整它们的大小,我可以重新加入它们以在服务器端创建 gif?通过这种方式,服务器的 CPU 负载可以显着降低 IMO。我想...

标签: javascript php security gif imagick


【解决方案1】:

在客户端上拆分为帧、调整大小和重新加入所有内容对于非恶意用户来说是一个很好的减少服务器负载的方法。但是,攻击者仍然可以向您的 PHP 发送任何请求,包括带有大量大帧的巨大 gif - 他们根本不需要运行您的 javascript。因此,您完全正确,这是您应该减轻的潜在拒绝服务。用户输入不可信。

我想到了一些想法(请注意,我从未真正使用过动画 gif)。它们都围绕输入验证。

我不确定服务器究竟需要多长时间,但我猜这不是分割图像,更像是调整每一帧的大小。由于您的 javascript 应该在客户端调整 gif 的大小,因此收到的任何 gif 都应该只包含有限大小的帧。您可以拆分收到的 gif 并检查第一帧 - 如果它太大,您可以立即拒绝整个请求,这通常不会发生。 (也许你甚至不必拆分它来告诉大小?)

此外,您在客户端拆分并逐个发送它们的想法很棒,它承担了从服务器拆分的负载,您仍然可以(并且应该)检查服务器上帧的大小。请注意,在这种情况下,不仅第一个可能太大,攻击者可以发送任何内容。

您还可以检查帧数,并设置一个最大值,因为如果没有这个,无论哪种方式,这都是一种潜在的拒绝服务,因为攻击者可以发送一个 10x10 像素的 gif,但是 100 万帧(我'不确定gif格式是否有限制,但你明白了)。

另一种旁注是,无论您使用什么库来处理服务器上的 gif,都可能容易受到来自恶意图像的不同攻击。例如,Imagemagick 过去就有一些这样的漏洞。因此,为了使这更安全,除了随着库的新版本发布而进行的明显升级之外,您还可以在不同的服务器上运行图像处理,类似于后台作业处理器。仅允许对该服务器进行非常有限的访问并应用通用的强化最佳实践可以帮助遏制任何未来的妥协,并且还可以限制拒绝服务攻击的影响。

您还应该对这个图片上传端点应用某种速率限制,因为上传 1000 张 100 帧的图片甚至比 1 张 100000 帧的图片还要糟糕。因此,应该限制用户执行此操作的频率(或在给定时间范围内有多少张图像)。

【讨论】:

  • 您好!真的很感谢你的回答!是的,这就是我的想法,在过去的 12 个小时里,我创建了一个完全优化的服务器和客户端代码。都好!服务器负载没有增加,客户端在 100 帧图像上调整大小大约需要 2 秒!但现在我在 PHP 端面临“已超过允许的最大文件上传数”问题。默认为 20。如果我只是为我开发这个主题,但我已经有使用廉价主机的客户,那也没关系。我必须找到一种上传多种方式的方法,就像它是一个文件一样。
  • 更新:我完全放弃了使用 imagick,因为我意识到我不再需要它了。找到一个更新的 github 项目,使用 GD 库在 PHP 中将图像重新加入 gif 中。我通过将base64图像数据而不是文件发送到服务器来传递“已超过允许的最大文件上传数”。并使用 imagecreatefromstring(base64_decode(string)) 函数从中创建图像。我想我即将以最好的方式结束这一切。今天完成所有代码后,我将分享所有代码。
猜你喜欢
  • 2013-03-12
  • 1970-01-01
  • 1970-01-01
  • 2010-10-31
  • 2018-09-26
  • 2017-02-12
  • 2015-09-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多