Загрузка файлов: функция высокого риска
Функциональность загрузки файлов — одна из наиболее чувствительных к безопасности в веб-приложениях. Каждый загруженный файл потенциально вредоносен — это может быть скрипт, замаскированный под изображение, zip-бомба или файл с именем, нацеленным на эксплуатацию файловой системы.
Валидация типов файлов
Клиентская валидация
Атрибут accept на input ограничивает выбор файлов:
<input type="file" accept=".jpg,.jpeg,.png,.gif" />
Тестирование клиентской валидации:
- Выбрать файл валидного типа — должен быть принят
- Попробовать выбрать невалидный тип — должен быть отклонён
- Обойти атрибут accept (переименовать .exe в .jpg) — сервер должен перехватить
Серверная валидация
Сервер должен проверять реальное содержимое файла, а не только расширение:
| Тест-кейс | Файл | Ожидаемо |
|---|---|---|
| Валидное изображение | foto.jpg (настоящий JPEG) | Принять |
| Неправильное расширение | foto.txt (переименованный JPEG) | Отклонить или принять по содержимому |
| Ложное расширение | malware.jpg (на самом деле .exe) | Отклонить |
| Двойное расширение | image.jpg.php | Отклонить |
| SVG с JavaScript | vector.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 ГБ+
- Сервер должен обнаружить и отклонить бомбы декомпрессии
Упражнение: Аудит безопасности загрузки файлов
- Базовая функциональность: Загрузите валидные файлы каждого типа
- Обход типа: Переименуйте исполняемый файл под расширение изображения
- Ограничения размера: Загрузите файл чуть выше ограничения
- Специальные имена: Файлы с unicode, пробелами и спецсимволами
- Множество файлов: Загрузите максимум, затем попробуйте ещё один
- Отмена и повтор: Начните загрузку, отмените, попробуйте снова
- Сбой сети: Начните загрузку и отключите сеть
| Тест | Результат | Баг? | Серьёзность |
|---|---|---|---|
| .exe переименован в .jpg | Загружен успешно | Да | Критическая |
| 100 МБ (ограничение 10 МБ) | Ошибка только после полной загрузки | Да | Средняя |
Имя с ../ | Ошибка 500 сервера | Да | Критическая |
Тестирование после загрузки
После загрузки файла:
- Файл можно скачать без повреждений
- Хранится безопасно (не в публичной директории)
- URL не предсказуем (предотвращение перебора)
- Изображения отдаются с правильным Content-Type
- Нежелательные для просмотра файлы с
Content-Disposition: attachment
Ключевые выводы
- Загрузка файлов — функция высокого риска безопасности
- Серверная валидация должна проверять реальное содержимое, а не только расширения
- Валидация размера должна быть на стороне клиента
- Тестируйте имена со спецсимволами, unicode и path traversal
- Загруженные файлы не должны быть исполняемыми на сервере
- Тестируйте множественную загрузку, drag-and-drop, прогресс и отмену