EN Прислать проект
Все статьи

Загрузка файлов без сюрпризов

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

· 4 минБезопасностьИнфраструктура

Загрузка файлов в прототипе занимает десять строк: поле input type="file", запрос, сохранение в бакет, ссылка в базе. Работает с первого раза. А потом кто-то загружает файл на два гигабайта, HTML-страницу под видом аватарки или фотографию паспорта, которая открывается по ссылке любому, кто её угадал.

Каждый загруженный файл — это данные от незнакомца, которые ты хранишь и показываешь другим людям. Относиться к ним стоит соответственно.

Размер

Лимит размера ставится на каждом уровне: на прокси, в приложении и в правилах хранилища. Если файл грузится напрямую в хранилище по подписанной ссылке, лимит задаётся в условиях этой ссылки — иначе он не проверяется вообще.

Кроме лимита на файл, нужна квота на человека: сто файлов по допустимому размеру — тоже проблема, особенно если хранение оплачиваешь ты.

Тип

Расширение файла и заголовок Content-Type присылает клиент, и оба можно подделать. Тип определяется по содержимому — по первым байтам файла (сигнатуре), и сверяется со списком разрешённых. Список именно разрешённых: «всё, кроме .exe» не работает, потому что опасных форматов больше, чем ты вспомнишь.

Отдельно про SVG. Это не картинка, а XML, внутри которого может быть JavaScript. Открытый в браузере с твоего домена, он выполнится с доступом к твоим cookie. Если SVG не нужен — не принимай его. Если нужен — очищай или конвертируй в растр.

Имя и место

  • Имя файла придумываешь ты. Случайный идентификатор, а оригинальное имя — отдельным полем в базе. Имя от пользователя в пути к файлу — это ../ и перезапись чужих файлов.
  • Не в папку веб-сервера. Файлы лежат в объектном хранилище или вне каталога, который сервер раздаёт как статику. Иначе загруженный скрипт может оказаться исполняемым.
  • С отдельного домена. Пользовательский контент лучше раздавать с домена, не связанного с основным приложением. Тогда даже пропущенный HTML-файл не получит доступ к сессии.
  • С правильными заголовками. Для скачиваемых файлов — Content-Disposition: attachment, чтобы браузер не открывал их как страницу, и X-Content-Type-Options: nosniff, чтобы он не угадывал тип сам.

Публичные и приватные ссылки

Публичная ссылка подходит для того, что и так видно всем: аватарки, картинки товаров. Всё остальное — документы, сканы, вложения в переписке, счета — хранится в приватном бакете и отдаётся по подписанной ссылке с коротким сроком жизни. Ссылку выдаёт сервер, предварительно проверив, что человек имеет право на этот файл.

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

Вредоносные файлы

Если файлы, загруженные одним человеком, скачивают другие — вложения, документы, общие папки, — их стоит проверять антивирусом. Делай это в фоне: файл помечается как «на проверке» и недоступен другим, пока проверка не прошла. Многие облачные хранилища и сервисы умеют это из коробки.

Обработка изображений

Картинку, которую ты будешь показывать, лучше не хранить в исходном виде, а перекодировать.

  • Метаданные. EXIF с телефона часто содержит координаты, где сделан снимок. Перекодирование их убирает — и это вопрос приватности твоих пользователей, а не только безопасности.
  • Размер в пикселях. Файл в несколько килобайт может разворачиваться в изображение, которому не хватит памяти сервера. Проверяй размеры до декодирования и ставь потолок.
  • Изоляция. Библиотеки обработки изображений регулярно получают исправления уязвимостей. Обновляй их и запускай обработку в отдельном процессе или задаче с ограничением памяти и времени.

Не забудь про удаление

Удалил аккаунт — удали и файлы. Заказ отменён — вложения не должны висеть в хранилище годами. Файлы без владельца — это и лишние расходы, и данные, которые ты обязан защищать, хотя уже не используешь.

SUBXCAT может проверить, как устроена загрузка файлов в твоём продукте, и привести её в порядок без смены хранилища.

Хочешь, сделаем это за тебя?

Расскажи о проекте ассистенту — через пять минут будет примерная смета, через 48 часов разбор.

Созвон с командой 20 минут: инженер, дизайнер и маркетолог посмотрят на проект вместе с тобой.
Записаться на звонок