Как предотвратить изображение бомбы с ImageMagick?
В настоящее время я использую библиотеку Imagick на PHP и использую функцию изменения размера Image Magick. Я только что узнал о декомпрессионных бомбах и о том, как ImageMagick уязвим к нему.
Я проверил, как мы можем пропинговать изображение и проверить размеры изображения, фактически не загружая его в память / диск. Также безопаснее ограничить ограничения памяти и диска 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
3 ответа
Установка предела "Область ресурса" устанавливает только размер, при котором изображения не хранятся в памяти, а вместо этого выгружаются на диск. Если вы хотите использовать этот параметр для фактического ограничения максимального размера изображения, которое может быть открыто, вам также необходимо установить ограничение "Ресурсный диск".
Приведенный ниже код правильно отображает ошибку выделения памяти для изображений бомб, взятых отсюда.
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";
}
Выход:
Исключение: Ошибка выделения памяти `./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 читает этот файл и использует эти настройки, если они не заданы в программе, что может быть более удобным способом их настройки, поскольку вы можете изменить их для каждой машины.
Это лишает меня возможности справиться с этим должным образом.
Это делает невозможным для вас справиться с этим в одном процессе. Вы можете справиться с этим просто отлично, запустив обработку изображения в фоновом режиме.
Лично я думаю, что в любом случае использование Imagick на сервере, доступ к которому напрямую осуществляется через веб-браузеры, является чокнутым. Гораздо безопаснее запускать его как фоновую задачу (управляемую чем-то вроде http://supervisord.org/) и связываться с этой фоновой задачей через очередь заданий, которые необходимо обработать.
Это не только решает проблему "плохие изображения может обрушить мой веб-сайт", но и значительно упрощает мониторинг использования ресурсов или переводит обработку изображений на компьютер с более быстрым ЦП, чем требуется для веб-сервера переднего плана.
Источник - я поддерживаю расширение Imagick, и недавно я добавил это в readme Imagick:
Безопасность
Расширение PHP Imagick работает, вызывая библиотеку ImageMagick. Хотя разработчики ImageMagick стараются избегать ошибок, неизбежно, что некоторые ошибки будут присутствовать в коде. ImageMagick также использует множество сторонних библиотек для открытия, чтения и манипулирования файлами. Авторы этих библиотек также заботятся о написании своего кода. Однако все делают ошибки, и неизбежно будут присутствовать некоторые ошибки.
Поскольку ImageMagick используется для обработки изображений, хакеры могут создавать изображения, содержащие недопустимые данные, чтобы попытаться использовать эти ошибки. Из-за этого мы рекомендуем следующее:
1) Не запускайте Imagick на сервере, который напрямую доступен за пределами вашей сети. Лучше либо использовать его в качестве фоновой задачи, используя что-то вроде SupervisorD, либо запустить его на отдельном сервере, который не имеет прямого доступа в Интернете.
Это сделает хакерам трудным использование ошибки, даже если она должна существовать в библиотеках, которые использует ImageMagick.
2) Запустите его как процесс с очень низкими привилегиями. Насколько это возможно, файлы и системные ресурсы, доступные для PHP-скрипта, из которого вызывается Imagick, должны быть заблокированы.
3) Проверьте результат обработки изображения в действительном файле изображения, прежде чем отобразить его пользователю. В крайне маловероятном случае, когда хакер может передавать произвольные файлы на выход Imagick, разумной мерой предосторожности является проверка того, что это файл изображения, а не исходный код отправляемого приложения.
Начиная с ImageMagick-6.9.0-1, добавлены ограничения ресурсов "ширина" и "высота". В командной строке используйте "-limit width 32000" и т. Д. PNG-декодер ImageMagick будет работать без распаковки изображения, если ширина или высота превышает указанный предел.
Декодер PNG не будет пытаться распаковывать изображения, ширина или высота которых превышает пределы.
Ресурс "area" доступен в более ранних версиях ImageMagick (и Imagick); однако декодер PNG не отклоняет изображения, основываясь на пределе "площади" (см. комментарий Danack).
В версиях ImageMagick ранее 6.9.0 ограничения ширины и высоты берутся из libpng и зависят от версии libpng. Текущие версии libpng (1.0.16 и более поздние версии, 1.2.6 и более поздние версии, 1.5.22 и более поздние версии и 1.6.17 и более поздние версии) устанавливают ограничения в 1 000 000 столбцов и ширину. В версиях с 1.2.0 по 1.2.5, с 1.5.0 по 1.5.23 и с 1.6.0 по 1.6.16 ограничения составляли по умолчанию 2,7 млрд строк и столбцов.
Ищите RESOURCETYPE_AREA в Imagick (я не вижу _WIDTH или _HEIGHT в руководстве, на которое вы ссылались, поэтому необходимо обновить либо Imagick, либо его руководство). Так что постарайтесь
IMagick::setResourceLimit(IMagick::RESOURCETYPE_AREA , 100M);
установить предел в 100 мегапикселей. Надеемся, что некоторые будущие версии Imagick будут поддерживать RESOURCETYPE_WIDTH и RESOURCETYPE_HEIGHT, чтобы обеспечить лучшее решение для уязвимости декомпрессионной бомбы. Посмотрите ответ Danack о настройке их с текущей версией IMagick.
все, что я получаю, является ошибкой сегментации, никакие исключения не брошены
Я предполагаю, что ошибка вашего сегмента в том, что ресурсы слишком малы для работы ImageMagick (и связанных с ним делегатов). Значение ресурса указывается в байтах, а не в мегабайтах.
Imagick выдает исключение, если ресурс достигнут. Обычно что-то вроде...
"ресурс кеша исчерпан"
Декомпрессионные бомбы, или Zip-Bombs, чрезвычайно трудно идентифицировать. Чем вы занимаетесь ping
-изображение изображения и установка лимитов ресурсов - это правильный курс действий. Я бы в общих чертах обозначил решение как...
// Define limits in application settings, or bootstrap (not dynamically!)
define('MY_MAGICK_MEMORY_LIMIT', 5e+8);
// Repeat for AREA, DISK, & etc.
// In application
$image = new Imagick(); // allocate IM structrues
// Set limits on instance
$image->setResourceLimit(Imagick::RESOURCETYPE_MEMORY, MY_MEMORY_LIMIT);
// Repeat for RESOURCETYPE_AREA, RESOURCETYPE_DISK, & etc.
$filename = 'input.png';
if($image->ping($filename)) {
// Validate that this image is what your expecting
// ...
try {
$image->read($filename); // <-- Bomb will explode here
$image->resizeImage(320,240,Imagick::FILTER_LANCZOS,1);
} catch( ImageickException $err ) {
// Handle error
}
}
unset($image)
Если вы не доверяете декомпрессии, вы можете использовать Imagick::getImageCompression во время проверки ping, чтобы проверить, какое сжатие требуется для изображения. Тип сжатия будет целым числом, которое будет соответствовать следующему перечислению...
typedef enum
{
UndefinedCompression,
B44ACompression,
B44Compression,
BZipCompression,
DXT1Compression,
DXT3Compression,
DXT5Compression,
FaxCompression,
Group4Compression,
JBIG1Compression,
JBIG2Compression,
JPEG2000Compression,
JPEGCompression,
LosslessJPEGCompression,
LZMACompression,
LZWCompression,
NoCompression,
PizCompression,
Pxr24Compression,
RLECompression,
ZipCompression,
ZipSCompression
} CompressionType;
MagickStudio (написанный на PERL) предлагает хорошую отправную точку для ограничений ресурсов по умолчанию и того, как они проверяются по загруженным изображениям (поиск Ping
.)