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

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

Published: 2026-05-31 · Source: https://subxcat.com/ru/articles/safe-file-uploads · Author: SUBXCAT

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

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

## Размер

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

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

## Тип

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

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

## Имя и место

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

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

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

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

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

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

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

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

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

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

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

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