php - 如何使用 ImageMagick 防止图像炸弹?

标签 php imagemagick image-resizing imagick imagemagick-identify

我目前在 PHP 上使用 Imagick 库并使用 Image Magick 的调整大小功能。我刚刚了解了减压炸弹以及 ImageMagick 如何容易受到它的攻击。<​​/p>

我已经检查了如何在不实际将图像加载到内存/磁盘的情况下对图像执行 ping 操作并验证图像的尺寸。限制 ImageMagick 的内存和磁盘限制也更安全,这样它就不会在磁盘上写入一个巨大的文件。

我已经阅读并可以使用 setResourceLimit() 来实现。 http://php.net/manual/en/imagick.setresourcelimit.php

IMagick::setResourceLimit(IMagick::RESOURCETYPE_MEMORY , 100);
IMagick::setResourceLimit(IMagick::RESOURCETYPE_DISK , 100);

$thumb = new Imagick('image.png');
$thumb->resizeImage(320,240,Imagick::FILTER_LANCZOS,1);

然而,在设置磁盘和内存限制后,如果图像确实达到了这个限制,我得到的只是一个段错误错误,不会抛出任何异常。这让我无法妥善处理。

更新:

这是我使用的包版本:

dpkg -l | grep magick
ii  imagemagick-common                    8:6.6.9.7-5ubuntu3.3              image manipulation programs -- infrastructure
ii  libmagickcore4                        8:6.6.9.7-5ubuntu3.3              low-level image manipulation library
ii  libmagickwand4                        8:6.6.9.7-5ubuntu3.3              image manipulation library
ii  php5-imagick                          3.1.0~rc1-1                       ImageMagick module for php5

最佳答案

设置“资源区”限制仅设置图像不保存在内存中的大小,而是分页到磁盘。如果您想使用该设置来实际限制可以打开的最大图像大小,您还需要设置“资源磁盘”限制。

下面的代码正确给出了图像炸弹的内存分配错误 from here .

try {
    Imagick::setResourceLimit(Imagick::RESOURCETYPE_AREA, 2000 * 2000);
    Imagick::setResourceLimit(Imagick::RESOURCETYPE_DISK, 2000 * 2000);

    $imagick = new Imagick("./picture-100M-6000x6000.png");
    $imagick->modulateImage(100, 50, 120);
    $imagick->writeImage("./output.png");

    echo "Complete";
}
catch(\Exception $e) {
    echo "Exception: ".$e->getMessage()."\n";
}

输出是:

Exception: Memory allocation failed `./picture-100M-6000x6000.png' @ error/png.c/MagickPNGErrorHandler/1630

如果你想设置宽度和高度资源,并且有一个版本的 ImageMagick >= 6.9.0-1 你应该能够直接使用值 WidthResource = 9, HeightResource = 10

//Set max image width of 2000
Imagick::setResourceLimit(9, 2000);
//Set max image height of 1000
Imagick::setResourceLimit(10, 1000);

这些不必以编程方式设置,您可以通过 policy.xml 设置它们随 ImageMagick 安装的文件。如果程序中没有设置,ImageMagick 会读取该文件并使用这些设置 - 这可能是一种更方便的设置方式,因为您可以在每台机器上更改它们。

This makes it impossible for me to handle it properly.

这让您无法在同一个进程中处理它。您可以通过在后台任务中运行图像处理来很好地处理它。

我个人认为无论如何,在可由网络浏览器直接访问的服务器中使用 Imagick 是疯狂的。将它作为后台任务运行(由 http://supervisord.org/ 之类的东西管理)并通过需要处理的作业队列与该后台任务通信要安全得多。

这不仅解决了“糟糕的图像会导致我的网站瘫痪”的问题,还使监控资源使用情况变得更加容易,或者将图像处理转移到 CPU 比 Web 前端服务器更快的机器上需要。

来源 - 我是 Imagick 扩展的维护者,我最近将其添加到 Imagick 自述文件中:

Security

The PHP extension Imagick works by calling the ImageMagick library. Although the ImageMagick developers take good care in avoiding bugs it is inevitable that some bugs will be present in the code. ImageMagick also uses a lot of third party libraries to open, read and manipulate files. The writers of these libraries also take care when writing their code. However everyone makes mistakes and there will inevitably be some bugs present.

Because ImageMagick is used to process images it is feasibly possible for hackers to create images that contain invalid data to attempt to exploit these bugs. Because of this we recommend the following:

1) Do not run Imagick in a server that is directly accessible from outside your network. It is better to either use it as a background task using something like SupervisorD or to run it in a separate server that is not directly access on the internet.

Doing this will make it difficult for hackers to exploit a bug, even if one should exist in the libraries that ImageMagick is using.

2) Run it as a very low privileged process. As much as possible the files and system resources accessible to the PHP script that Imagick is being called from should be locked down.

3) Check the result of the image processing is a valid image file before displaying it to the user. In the extremely unlikely event that a hacker is able to pipe arbitrary files to the output of Imagick, checking that it is an image file, and not the source code of your application that is being sent, is a sensible precaution.

关于php - 如何使用 ImageMagick 防止图像炸弹?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31543899/

相关文章:

python - 使用 python 库填充图像中的穿孔形状?

ios - 缩放时调整 UIScrollView 的内容

css - 在容器中的特定位置设置图像

php - Magento - 如何使用从自定义 MySQL 表获取数据的网格表创建 Adminhtml 页面

php - 如何在 PHPmailer 中显示所有选中的复选框

java - 使用 im4java 创建透明 Canvas

imagemagick - 如何使用 imagemagick/montage 使图像等距?

javascript - 如何使用 javascript 调整 Base64 编码的数据 URI PNG 的大小?

php - 如何在自己的服务器上拥有 Github?

php - 如何在注册表单中显示错误消息?