Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Як безпечно зберігати й віддавати файли користувачів у Laravel?

Два типи файлів - два способи зберігання:

  • публічні (аватари, зображення статей) - диск public чи публічний бакет; доступні за прямим URL усім;
  • приватні (рахунки, документи, вкладення в листуванні) - диск local (каталог storage/app/private) чи приватний бакет; недоступні за прямим URL.

Типова помилка - класти все на public. php artisan storage:link робить storage/app/public доступним з вебу. Документ, збережений туди, відкривається будь-ким, хто вгадає чи отримає шлях - а шляхи потрапляють у листи, логи, історію браузера.

Віддача приватних файлів - через контролер з перевіркою прав:

Route::get('/documents/{document}', function (Document $document) {
    Gate::authorize('view', $document);

    return Storage::disk('private')->download($document->path, $document->original_name);
})->middleware('auth');

Для хмарних сховищ - тимчасове підписане посилання, файл віддає саме сховище:

return redirect(Storage::disk('s3')->temporaryUrl($document->path, now()->plus(minutes: 5)));

Правила збереження:

  • власні назви файлів - $file->store('documents') генерує випадкову назву. Оригінальну назву зберегти в базі для показу, але не використовувати як шлях (обхід шляху, перезапис чужих файлів, спецсимволи);
  • перевірка вмісту, а не розширення: правило mimes:pdf,jpg перевіряє MIME за вмістом; extensions: - лише розширення. Для зображень корисно ще й перекодувати (знімає вбудовані скрипти й метадані з геолокацією);
  • обмеження розміру - правило max: і ліміти PHP/вебсервера;
  • жодного виконання в каталогах завантажень: вебсервер не повинен виконувати .php з storage чи публічних каталогів;
  • Content-Disposition: attachment для файлів, які не повинні відкриватися в браузері (HTML чи SVG від користувача, відкриті як сторінка вашого домену, - XSS).

Видимість у хмарі: у Laravel/Flysystem файли за замовчуванням приватні; 'visibility' => 'public' - свідоме рішення. Бакет без публічного доступу на рівні налаштувань провайдера - додатковий захист від помилки в коді.

Видалення: при видаленні запису видаляти й файл (і навпаки - прибирати «осиротілі» файли), інакше дані, які користувач вважає видаленими, лишаються доступними.

Докладніше в документації: Laravel: видимість файлів

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання