Загрузка файлов: функция высокого риска

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

Валидация типов файлов

Клиентская валидация

Атрибут accept на input ограничивает выбор файлов:

<input type="file" accept=".jpg,.jpeg,.png,.gif" />

Тестирование клиентской валидации:

  1. Выбрать файл валидного типа — должен быть принят
  2. Попробовать выбрать невалидный тип — должен быть отклонён
  3. Обойти атрибут accept (переименовать .exe в .jpg) — сервер должен перехватить

Серверная валидация

Сервер должен проверять реальное содержимое файла, а не только расширение:

Тест-кейсФайлОжидаемо
Валидное изображениеfoto.jpg (настоящий JPEG)Принять
Неправильное расширениеfoto.txt (переименованный JPEG)Отклонить или принять по содержимому
Ложное расширениеmalware.jpg (на самом деле .exe)Отклонить
Двойное расширениеimage.jpg.phpОтклонить
SVG с JavaScriptvector.svg (содержит <script>)Санитизировать или отклонить

Тестирование размера файлов

Тест-кейсОжидаемо
Под ограничениемПринять и загрузить
На точной границеПринять (граничное значение)
На 1 байт вышеОтклонить с понятным сообщением
Очень большой (1 ГБ+)Отклонить быстро
Пустой (0 байт)Отклонить или принять по спецификации

Тестирование функциональности загрузки

Прогресс и обратная связь

  • Появляется ли индикатор прогресса при загрузке?
  • Точен ли процент?
  • Можно ли отменить текущую загрузку?
  • Что происходит при переходе на другую страницу во время загрузки?

Загрузка нескольких файлов

  • Можно ли выбрать несколько файлов одновременно?
  • Есть ли максимальное количество?
  • Можно ли удалить отдельные файлы перед отправкой?
  • Соблюдается ли суммарное ограничение размера?

Drag and drop

  • Можно ли перетащить файлы в область загрузки?
  • Подсвечивается ли зона при перетаскивании?
  • Валидируются ли перетащенные файлы так же, как выбранные?

Спецсимволы в именах файлов

Тестируйте с такими паттернами:

  • Пробелы: мой документ.pdf
  • Unicode: документ.pdf, 档案.pdf
  • Спецсимволы: файл (1).jpg
  • Очень длинные имена: 255+ символов
  • Без расширения: README
  • Зарезервированные имена (Windows): CON.txt, NUL.jpg

Тестирование безопасности загрузки файлов

Загрузка исполняемых файлов

Попытайтесь загрузить файлы, которые могут выполниться на сервере:

  • .php, .asp, .jsp — серверные скрипты
  • .html — может содержать JavaScript
  • .svg — может содержать встроенные скрипты
  • .exe, .bat, .sh — системные исполняемые файлы

Path traversal

Тестируйте имена файлов для выхода из директории:

  • ../../../etc/passwd
  • ..\\..\\windows\\system.ini

Тестирование zip-бомб

Zip-бомба — маленький архив, расширяющийся до огромного размера:

  • Загрузите zip в 1 КБ, расширяющийся до 1 ГБ+
  • Сервер должен обнаружить и отклонить бомбы декомпрессии

Упражнение: Аудит безопасности загрузки файлов

  1. Базовая функциональность: Загрузите валидные файлы каждого типа
  2. Обход типа: Переименуйте исполняемый файл под расширение изображения
  3. Ограничения размера: Загрузите файл чуть выше ограничения
  4. Специальные имена: Файлы с unicode, пробелами и спецсимволами
  5. Множество файлов: Загрузите максимум, затем попробуйте ещё один
  6. Отмена и повтор: Начните загрузку, отмените, попробуйте снова
  7. Сбой сети: Начните загрузку и отключите сеть
ТестРезультатБаг?Серьёзность
.exe переименован в .jpgЗагружен успешноДаКритическая
100 МБ (ограничение 10 МБ)Ошибка только после полной загрузкиДаСредняя
Имя с ../Ошибка 500 сервераДаКритическая

Тестирование после загрузки

После загрузки файла:

  1. Файл можно скачать без повреждений
  2. Хранится безопасно (не в публичной директории)
  3. URL не предсказуем (предотвращение перебора)
  4. Изображения отдаются с правильным Content-Type
  5. Нежелательные для просмотра файлы с Content-Disposition: attachment

Ключевые выводы

  • Загрузка файлов — функция высокого риска безопасности
  • Серверная валидация должна проверять реальное содержимое, а не только расширения
  • Валидация размера должна быть на стороне клиента
  • Тестируйте имена со спецсимволами, unicode и path traversal
  • Загруженные файлы не должны быть исполняемыми на сервере
  • Тестируйте множественную загрузку, drag-and-drop, прогресс и отмену