Сервис принимает загруженный файл, проверяя только его расширение. Почему этого недостаточно для безопасной границы обработки?
Расширение — это управляемая пользователем метка, а не доказательство фактического типа содержимого. Злоумышленник может переименовать опасный файл или передать данные, которые разные компоненты интерпретируют по-разному. Безопасная граница должна проверять содержимое файла перед передачей его потенциально уязвимым обработчикам.
Проверка расширения появилась как простой способ отделить ожидаемые форматы от остальных. Она удобна для пользовательского интерфейса и предварительной фильтрации, но не предназначена для установления доверия: имя файла и его расширение задаются внешним источником.
По мере появления загрузки файлов, предпросмотра, конвертации и автоматического анализа стало очевидно, что один файл проходит через несколько независимых компонентов. Если они по-разному определяют его тип, атакующий может использовать расхождение между проверкой на входе и последующей обработкой.
Расширение можно изменить без изменения содержимого. Например, файл с исполняемым содержимым можно назвать изображением, а файл с вредоносной структурой — документом допустимого формата.
Риск возникает не только при запуске файла. Уязвимость может находиться в библиотеке разбора изображений, архивов, документов или в компоненте предварительного просмотра. Если такой компонент доверяет внешнему имени либо неправильно обрабатывает содержимое, загрузка приводит к выполнению кода, утечке данных, отказу в обслуживании или обходу ограничений.
Расширение следует использовать только как вспомогательную проверку. Основная проверка должна анализировать фактическое содержимое: допустим ли формат, соответствует ли структура ожидаемому типу, не нарушены ли ограничения размера, вложенности, количества элементов и других ресурсов.
Нельзя считать MIME-тип из запроса достаточным доказательством: он также передаётся клиентом. Проверка сигнатуры файла полезнее, но не универсальна: некоторые форматы имеют неоднозначные или сложные структуры, а корректная сигнатура ещё не гарантирует отсутствие опасного содержимого.
Безопасная архитектура обычно включает несколько мер: хранение загруженных данных вне каталога, откуда они могут исполняться или напрямую раздаваться; случайные серверные имена; ограничение размера и времени обработки; разбор в изолированном процессе с минимальными привилегиями; проверку формата специализированным парсером; антивирусный анализ или очистку содержимого, если это соответствует требованиям.
Проверки должны выполняться на каждой границе, где компонент начинает доверять данным. Если шлюз проверил имя файла, это не освобождает сервис конвертации от собственной проверки: между компонентами могли измениться формат, контекст обработки или набор разрешённых возможностей.
Усиление контроля повышает стоимость и задержку обработки, а строгая проверка может отклонять легитимные файлы сложных форматов. Поэтому разрешённые форматы, лимиты и поведение при ошибке нужно выбирать исходя из бизнес-сценария. При сомнении безопаснее отклонить файл либо передать его в изолированный этап ручной или специализированной обработки.
Сервис принимает изображения профиля. Первый вариант проверял расширение, сохранял исходное имя, а затем передавал файл библиотеке создания миниатюр. Он был простым и быстрым, но позволял подменить расширение, атаковать парсер изображений и создать риск публикации файла под контролируемым именем.
Второй вариант добавлял проверку MIME-типа. Это почти не увеличивало задержку, но не устраняло проблему: тип можно подделать, а разные компоненты могли определить содержимое неодинаково.
Выбранный вариант сохранял файл во временное хранилище вне публичного каталога, ограничивал размер, проверял структуру поддерживаемых форматов, создавал новое изображение через изолированный обработчик, удалял исходный файл после успешной обработки и выдавал результат под серверным идентификатором. Такой вариант сложнее, зато граница между внешними данными и парсером стала явной, а последствия компрометации обработчика ограничились его изолированной средой.
Нет. Сигнатура подтверждает лишь отдельный признак формата. Она не доказывает, что весь файл корректен, безопасен для конкретного парсера, не содержит опасных конструкций или не вызовет чрезмерное потребление ресурсов. Нужны структурная проверка, ограничения ресурсов и безопасная обработка.
Новое имя предотвращает часть атак, связанных с путями, перезаписью файлов и публичными именами, но не исправляет опасное содержимое. Уязвимый обработчик всё равно получит вредоносный файл, даже если тот назван случайным идентификатором без расширения.
Да, если результат передаётся другому доверенному компоненту или становится доступен пользователю. Конвертер может сохранить неожиданные метаданные, создать слишком большой результат или сформировать файл, который следующий обработчик интерпретирует опасно. Результат следует проверять согласно требованиям следующей границы, а не автоматически считать безопасным только потому, что он создан внутренним сервисом.