86점
Понимание методов Pillow open(), verify(), load() с точки зрения безопасности
Загрузка изображения — это не просто «получение файла», а передача внешнего ввода в декодер (парсер). Поэтому важнее не то, что делают методы Pillow, а когда они вызываются (то есть когда открывается поверхность атаки).
open() — это не «поднятие пикселей»
Image.open() работает лениво. Он открывает файл и определяет его формат, но пиксельные данные могут не считываться. Файл может оставаться открытым.
В безопасной и операционной практике open() используется так:
- Сначала с помощью
open()получаем лёгкую информацию: формат, ширину/высоту - На основе политики блокируем: разрешённые форматы, максимальное разрешение/число пикселей, лимит размера загрузки
- Затем переходим к следующему этапу (проверка/декодирование)
То есть open() безопасно использовать как инструмент для извлечения информации до декодирования.
Что гарантирует verify() и что не гарантирует
verify() пытается убедиться, что файл не повреждён, но не декодирует данные изображения. Если обнаружены проблемы, генерируется исключение, и чтобы продолжить работу с изображением, его нужно открыть заново.
Выводы с точки зрения безопасности:
- Плюс: быстро отфильтровывает повреждённые файлы, не выполняя тяжёлого декодирования
- Минус: прохождение
verify()не означает полной безопасности; проблемы могут проявиться только приload()
load() опасен, если вызывать его в процессе проверки
load() действительно декодирует (включая распаковку) и загружает пиксели в память. Это сразу создаёт поверхность DoS-атаки, так как даже маленький файл может распаковаться в огромный объём данных.
Pillow предупреждает о «декомпрессионной бомбе» и имеет защиту по умолчанию (например, порог 128 Мп). Django по той же причине при валидации изображений использует verify() вместо load(). В коде есть комментарий: «load() загружает всё изображение в память и может стать вектором DoS».
При использовании Django/DRF: ImageField уже вызывает verify() — дублирование может быть избыточным
Валидация ImageField в Django использует Image.open() + verify(). Аналогично serializers.ImageField в DRF делегирует проверку Django.
Если вы уже используете serializers.ImageField, то:
- Вызов
verify()вvalidate()обычно избыточен - Для более строгой бизнес-валидации можно принимать файл через
FileFieldи самостоятельно строить пайплайн проверки, что делает ответственность более прозрачной
Как обеспечить «безопасность» загруженных файлов

Практичное решение:
- Не используйте оригинальный файл напрямую: декодируйте его на сервере и сохраняйте только результат.
- С помощью
open()считываем лёгкую информацию (формат, размеры) и применяем первичную фильтрацию. verify()удаляет явно повреждённые файлы.- В ограниченной среде декодируем и нормализуем в стандартные пиксели (RGB/RGBA).
- Перекодируем в выбранный сервером формат и сохраняем новый файл.
- Сервис хранит и обслуживает только серверно перекодированный файл.
Преимущество: сервер контролирует конечный формат, удаляя лишние метаданные и аномалии. Однако перекодирование всё равно включает load(), поэтому важно установить ограничения по количеству пикселей/памяти и выполнять это в изолированном процессе.
Итоги
open()— «идентификация + сбор лёгкой информации» (пиксели могут отсутствовать)verify()— «первичный фильтр повреждений» (без декодирования, при дальнейшей работе требуется повторное открытие)load()— «начало декодирования/использования памяти» (не использовать в процессе проверки)- Практический подход к безопасной загрузке: доверять только серверно перекодированным файлам (с ограничениями и изоляцией)
Смотрите также: