Подтвердить что ты не робот

Безопасное отображение изображений

Уважаемый коллега настаивает на том, что хранение изображений на моем сервере небезопасно, особенно если файловая структура легко догадаться (поскольку у нас есть галереи изображений, созданные пользователями, схема именования легко отслеживается).

Вместо этого он рекомендует хранить изображения над корнем и обслуживать их, используя fread или fputthrough.

Я не могу понять, какими будут риски, или почему они будут устранены при использовании script.
Накладные расходы такого script звучат нелепо.

Я действительно понимаю, что изображения должны быть проверены перед сохранением на сервере, и с этой целью я использую imagemagick, чтобы сделать небольшое преобразование и сохранить в jpeg, - который, как я мог бы догадаться, должен избавиться от любого шлака.

Итак, вопросы великим умом на SO:

  • Существуют ли какие-либо проблемы с безопасностью при локальном хранении изображений с легко отслеживаемыми путями?
  • Является ли мой метод проверки изображений с помощью IM безопасным?
  • Есть ли причина использовать PHP для работы с изображениями?
  • Являются ли накладные расходы на использование PHP действительно существенным?
  • Будет ли использование CDN изменить ситуацию, поскольку безопасность идет (я не хочу)?
  • Я что-то пропустил?

Спасибо всем!

4b9b3361

Ответ 1

Я подозреваю, что то, о чем говорит ваш друг, - это не просто показ изображений, а, в частности, обслуживание изображений, предоставляемых пользователем. Существует ряд проблем безопасности при обслуживании контента, поставляемого пользователем. В случае с изображениями существует несколько способов использования загрузки изображения, чтобы заставить веб-сервер выполнять код. Некоторые из наиболее известных включают:

  • Файл "GIFAR". По сути, это файл GIF и файл jar, объединенный. Поскольку информация индекса для GIF находится в начале и что для файла jar находится в конце, два типа файлов могут быть объединены, и результат будет действительным GIF и действительным JAR.
  • Несколько расширений файлов. Веб-серверы поддерживают несколько расширений файлов, что позволяет делать такие вещи, как интернационализация. Например, файл с именем page.html.fr может отображаться на французской версии страницы. Файл с расширением image.php.jpg или даже image.php.123 может быть исполняемым как PHP script, в зависимости от конфигурации сервера.
  • Переполнение буфера. Форматы файлов изображений обычно содержат заголовок в начале, который описывает размер и формат файла. Занижение размера позволяет злоумышленникам создавать атаку переполнения буфера.

Все эти примеры приводят к возможности выполнять код в качестве веб-сервера. Хотя функциональность сайта требует возможности загружать файлы, их хранение в каталогах, которые напрямую не доступны по URL-адресу, затрудняет их использование. Аналогично, использование script для их обслуживания, а не для веб-серверов. Обработчики MIME гарантируют, что изображения обрабатываются как поток данных, а не потенциально исполняемый файл.

Является ли эта большая безопасность смешной, зависит от количества пользователей, характера собранных данных и их тривиальности. По крайней мере, злоумышленник хотел бы получить пароли пользователей из-за тенденции их синхронизации. Пользователь на вашем сайте, чей пароль ABC123, вероятно, будет использовать тот же пароль для электронной почты, социальных сайтов и возможных банковских и финансовых сайтов. Помимо паролей, если данные, которые вы собираете о своих пользователях, идентифицируются лично или имеют другую рыночную стоимость, или если у вас просто большое количество пользователей, то вы должны предположить, что сайт станет целью. Это означает, что нужно быть более осторожным, обслуживая файлы изображений, предоставленные пользователем, правильно их проверить или и то, и другое.

У меня нет хорошего ответа на вопрос, будет ли использование imagemagick решать проблемы безопасности. По крайней мере, обязательно используйте текущую версию, потому что быстрый поиск показал ряд известных уязвимостей. Помните, что файлы, о которых вам нужно беспокоиться, могут взорвать imagemagick, даже если они не используют одну из известных уязвимостей, поэтому обязательно получите ДЕЙСТВИТЕЛЬНО хорошее захват ошибок.

Ответ 2

Если изображения не являются частными, т.е. вы можете видеть их достаточно легко, вы просто не хотите, чтобы кто-то читал их все по желанию, давая каждому уникальное имя, может быть достаточно.

Если есть несколько тысяч (и это кажется вероятным), то создание иерархии каталогов, в которую они хранятся, также может помочь ускорить доступ, при этом увеличивая пространство поиска настолько, что они не будут найдены случайным поиском, Например: файл под названием 347168a5d9b4ac5eb386e396f68b2231.jpg может быть помещен в каталог: /images/ 34/71/68/347168a5d9b4ac5eb386e396f68b2231.jpg Многоуровневый каталог ускоряет доступ, избегая сканирования тысяч записей в каталоге, а рандомизированное имя (хранящееся в базе данных, прикрепленной к списку пользователей в галерее) останавливает случайные файлы.

Ответ 3

Накладные расходы такого script звучат нелепо.

То же самое здесь. Если изображения общедоступны, я не вижу абсолютно никаких оснований для этого.

Если они не являются общедоступными (т.е. должны быть доступны только для зарегистрированных пользователей), то нет пути вокруг того, как описывает ваш коллега (или используя X-Sendfile после выполнения проверки входа, которая сохраняет часть накладные расходы, если установлено необходимое программное обеспечение). Но если это не так, накладные расходы, необходимые для этого, сумасшедшие.

Ответ 4

Если вы определили, что вам действительно нужны изображения, чтобы быть в безопасности, вот что я использовал в комическом проекте (в основном я помещал кучу комиксов в каталог, а затем, когда какое-то время ударил, я бы позволил доступ к ним по одному)

//check if image should be accessed by the current request...

$fh=fopen($my_image,"rb");

if($fh==NULL){
        exit();
}
rewind($fh);
header("Content-Type: image/png");
header("Content-Length: " . filesize($fn));
fpassthru($fh);

fclose($fh);
exit();