Завантаження файлів - один із найризикованіших механізмів: нападник контролює і вміст, і ім'я файлу.
Основні загрози:
- Виконання коду:
shell.php(абоimage.php.jpgпри неправильно налаштованому сервері) у публічному каталозі - і нападник виконує довільний код. - Збережений XSS: SVG чи HTML-файл зі скриптом, відкритий з вашого домену.
- Перезапис файлів через ім'я на кшталт
../../config/app.php. - Відмова в обслуговуванні: величезні файли, «zip-бомби», зображення з гігантською роздільною здатністю.
Захист:
- Не довіряти імені й MIME-типу від клієнта. Генерувати власне ім'я (UUID) і визначати тип за вмістом. Розширення - з білого списку.
- Зберігати поза веб-коренем або в об'єктному сховищі (S3), а віддавати через контролер чи підписаний URL.
- Окремий домен для користувацьких файлів (
usercontent.example) - тоді навіть шкідливий HTML не має доступу до cookie основного сайту. - Заборонити виконання в каталозі завантажень на рівні веб-сервера.
- Обмежити розмір на всіх рівнях: веб-сервер, PHP (
upload_max_filesize,post_max_size), валідація застосунку. - Перекодувати зображення (зменшити, пересохранити через GD/Imagick) - це прибирає вбудовані дані й метадані (EXIF з геолокацією).
Content-Disposition: attachmentіX-Content-Type-Options: nosniffдля файлів, які не мають відкриватися в браузері.- Антивірусна перевірка для файлів, які завантажуватимуть інші користувачі.
$request->validate([
'avatar' => ['required', 'image', 'mimes:jpg,png,webp', 'max:2048', 'dimensions:max_width=4000,max_height=4000'],
]);
$path = $request->file('avatar')->store('avatars', 's3'); // ім'я генерує Laravel
SVG - окремий випадок: це XML зі скриптами. Його або забороняють, або санітизують, або віддають лише як attachment.