По фреймворкам
Безопасность Laravel — справочник по продакшн-харденингу
Справочник по продакшн-харденингу Laravel: чек-лист по приоритетам, опасные значения по умолчанию, рекомендации по областям — от секретов и конфигурации до авторизации и CVE зависимостей, плюс чек-лист самопроверки. Защитно, без шагов атаки.
Для: всех, кто ведёт Laravel в продакшне. Здесь нет шагов атаки — это рабочий справочник по харденингу: чек-лист по приоритетам, опасные значения по умолчанию, рекомендации по областям и самопроверка. Полную картину по фреймворкам смотрите на хабе безопасности по фреймворкам.
Чек-лист харденинга по приоритетам
Проходите таблицу сверху вниз. P0 — предпосылка для остального, P1 — самый частый источник инцидентов, P2 — постоянная эксплуатационная гигиена.
P0 ── Предпосылка (сначала это)
Отладка выключена в проде / секреты вне публичной поверхности с правами 600 / управление APP_KEY
P1 ── Главный источник инцидентов
Авторизация (Policy/Gate) / контроль Mass Assignment / CVE зависимостей / продакшн-кеширование
P2 ── Эксплуатационная гигиена
Сессии/CSRF/cookie / валидация загрузок / HTTPS, заголовки, ограничение частоты
| Приоритет | Мера | Конкретика (Laravel) |
|---|---|---|
| P0 | Отключить отладку в проде | APP_DEBUG=false / APP_ENV=production, закреплено через config:cache. Не раскрывать внутренности на странице ошибки |
| P0 | Секреты вне публичной поверхности | .env, резервные копии, ключи вне public/, права 600. storage/logs не публичны |
| P0 | Безопасно управлять APP_KEY | Лежит в основе шифрования, подписанных cookie, сессий. Внедряйте из окружения; ротация при утечке |
| P1 | Явная авторизация | Policy / Gate + authorize() / middleware can, с областью по владельцу/праву |
| P1 | Контроль Mass Assignment | Объявляйте $fillable; избегайте массового присваивания $request->all(), используйте validated() |
| P1 | Мониторинг CVE Composer | composer audit / osv-scanner; судите по работающей версии, быстро патчите |
| P1 | Продакшн-кеширование | config:cache route:cache view:cache для надёжных настроек + скорости |
| P2 | Безопасность сессий/cookie | Задайте secure http_only same_site; регенерируйте сессию при входе |
| P2 | Валидация загрузок | Проверяйте тип/размер, храните вне public/, без права на исполнение |
| P2 | HTTPS/заголовки/ограничение частоты | Принудительный HTTPS, HSTS, throttle на вход/API |
1. Секреты и APP_KEY (P0)
Laravel по умолчанию держит .env вне корня документов (в корне проекта). Инциденты в основном приходят из размещения секретов там, где им не место.
- Никогда не кладите
.env, дампы БД, резервные копии или файлы ключей вpublic/. Держите секреты вне корня приложения с правами 600 (только владелец). - Не выставляйте
storage/илиstorage/logs/(логи могут содержать секреты или персональные данные). Не коммитьте.envв репозиторий. APP_KEYлежит в основе шифрования, подписанных URL, шифрованных cookie и сессий. Внедряйте его из окружения и своевременно ротируйте при утечке (учтите, что это делает недействительными существующие шифрованные данные/сессии).
Общий принцип см. в держите секреты вне публичных каталогов; реальный кейс полной открытости — в полная открытость .env.
2. Продакшн-конфигурация: DEBUG, окружение, кеширование (P0)
APP_DEBUG=false / APP_ENV=production
Закрепите конфигурацию кешированием
php artisan config:cache (+ route:cache view:cache) делает применение настроек надёжным и ускоряет приложение. Внимание: после config:cache env() вне config/ возвращает null, поэтому обращайтесь к значениям через config('...') в приложении.Не выставляйте диагностические инструменты в проде
3. Авторизация: Broken Access Control (P1 — главный источник)
Самый частый продакшн-инцидент — «аутентифицирован, но не авторизован». Возможность войти не означает разрешения на действие.
Частое (опасное)
- нет авторизации — «залогинен = можно смотреть/обновлять»
- route-model binding достаёт ID другого пользователя
Model::create($request->all())принимает каждое поле- поле привилегии вроде
is_adminприсвоено из пользовательского ввода
Правильно
- Policy / Gate +
authorize()/ middlewarecan, каждый раз ограничивая по владельцу/праву - чтения тоже ограничены по владельцу (напр.
where('user_id', $me)) - ограничивайте ввод через
$request->validated()(FormRequest) - объявляйте
$fillable, чтобы блокировать Mass Assignment
См. что такое IDOR. Ключ — проверка владения на каждом пути чтения/обновления/удаления.
4. Инъекции и вывод
Eloquent / построитель запросов Laravel привязывает значения через плейсхолдеры, а Blade по умолчанию экранирует вывод. Правило — не отключайте эту защиту сами.
- SQL: не подмешивайте пользовательский ввод в
whereRaw/DB::rawконкатенацией строк. Даже когда нужен сырой SQL, используйте привязки (→ что такое SQL-инъекция). - XSS: Blade
{{ }}экранирует;{!! !!}— это сырой вывод. Не передавайте пользовательский ввод в{!! !!}. Если вывести HTML обязательно — только после санитизации (→ что такое XSS). - Валидация: проверяйте тип/диапазон/допустимые значения через FormRequest /
validate()перед использованием.
5. Сессии, CSRF, cookie (P2)
- CSRF: не отключайте глобально защиту CSRF в web-middleware. Используйте
@csrfв формах и корректную работу с токенами для SPA (→ что такое CSRF). - Cookie/сессии: задайте
secure(HTTPS),http_only,same_siteвconfig/session.php. Регенерируйте сессию при входе, чтобы предотвратить фиксацию (аутентификация Laravel регенерирует). - Перебор: применяйте
throttle/ лимиты попыток входа к логину.
6. Загрузка файлов и публичные файлы (P2)
- Проверяйте mime-тип, расширение и размер, и не доверяйте имени файла, присланному клиентом.
- Храните вне
public/(напр.storage/) без права на исполнение. Отдавайте наружу только необходимое, через контролируемый путь. - Ставьте авторизацию и на выдачу, чтобы последовательные прямые ссылки не доставали файл другого пользователя.
7. HTTPS, заголовки безопасности, ограничение частоты (P2)
- Принудительный HTTPS (
URL::forceScheme('https')и т. п.) + HSTS. За балансировщиком нагрузки используйтеTrustProxies, чтобы схема определялась корректно. - Заголовки безопасности (X-Content-Type-Options и т. п.; проектируйте CSP под вашу схему ассетов). Проверьте свой сайт с помощью проверки заголовков безопасности.
- Ограничение частоты: применяйте
throttleк входу, API и сбросу пароля.
8. Зависимости и версии (P1)
- Мониторьте CVE зависимостей Composer через
composer auditили osv-scanner, судите по работающей версии и быстро патчите (→ мониторинг CVE зависимостей · плейбук реагирования на уязвимости). - Держите Laravel и PHP на поддерживаемых версиях. Не оставляйте EOL-версии (накапливаются неисправимые дыры).
Проверка: ваш Laravel действительно укреплён?
Собрать — это не конец; готово только после того, как вы проверили. Это защитные самопроверки против вашего собственного сайта/окружения.
Секреты недостижимы по URL
/.env и /storage/logs/laravel.log и убедитесь, что они возвращают 404 (если достижимы — немедленно исправьте и ротируйте ключи).Нет открытой отладки в проде
Авторизация держится
Cookie/сессии и зависимости
composer audit чист.Взгляд этого сайта: даже при сильных значениях по умолчанию авторизация и зависимости — на вас
У Laravel много хороших значений по умолчанию, но авторизация — кто и что может делать — и свежесть зависимостей специфичны для приложения и эксплуатации, поэтому ни один фреймворк не защитит их автоматически. Инциденты, которые мы видим снова и снова, — не столько изощрённые атаки, сколько типы настроек/эксплуатации: «аутентифицирован, но нет проверки владения», «отладка открыта в проде», «секрет раскрыт». Поэтому центр тяжести — проработка таблицы выше сверху вниз и неброская работа: ограничивайте каждое чтение/обновление по владельцу и мониторьте зависимости на CVE.
Читать дальше
- Хаб: безопасность по фреймворкам · безопасность Next.js
- Секреты: держите секреты вне публичных каталогов · Кейс: полная открытость .env
- Авторизация / практика: что такое IDOR · плейбук реагирования на уязвимости · мониторинг CVE зависимостей
- Глоссарий: SQL-инъекция · XSS · CSRF
FAQ
QЧто нужно сделать в первую очередь, чтобы защитить Laravel?
Три пункта P0: (1) убедитесь, что APP_DEBUG=false в продакшне, и закрепите конфигурацию через config:cache; (2) держите .env и файлы секретов вне публичного каталога с жёсткими правами; (3) безопасно управляйте APP_KEY (он лежит в основе шифрования, подписанных cookie и сессий, так что при утечке — ротация). Это предпосылки для всего остального. Дальше переходите к авторизации (Policy/Gate) и мониторингу CVE зависимостей Composer.
QЧем опасно выкатить с APP_DEBUG=true?
При включённой отладке страница ошибки может показать не только стек вызовов, но и внутренние данные вроде значений конфигурации, переменных окружения и данных подключения. Атакующий может намеренно вызывать ошибки, чтобы их извлечь. В продакшне ставьте APP_DEBUG=false и APP_ENV=production и закрепляйте это через config:cache. Также не выставляйте наружу диагностические инструменты вроде Telescope или Debugbar в продакшне.
QПочему env() возвращает null после config:cache?
config:cache компилирует вашу конфигурацию в один файл для скорости, и после этого env(), вызванный вне файлов конфигурации, возвращает null (читается только .env на момент кеширования). Решение — использовать env() только внутри config/ и обращаться к значениям в приложении через config('...'). В продакшне кеширование config/route/view — норма: настройки применяются надёжно, а приложение ускоряется.
QКак не допустить «залогинен — значит, можно»?
Аутентификация (вход) и авторизация (можно ли выполнить действие) — разные вещи. В Laravel реализуйте Policy/Gate и используйте authorize() или middleware can, чтобы ограничивать каждое чтение/обновление/удаление по владельцу или праву. Также контролируйте Mass Assignment, объявляя $fillable, и избегайте массового присваивания $request->all(). Без этого подмена ID в URL достаёт данные другого пользователя (IDOR).
QКак управлять уязвимостями зависимостей Composer?
Мониторьте известные CVE машинно через composer audit или osv-scanner, судите по работающей версии и быстро патчите (решение по тому, что реально установлено, а не по объявлению в composer.json). Также держите Laravel и PHP на поддерживаемых версиях и не оставляйте EOL-версии. Свежесть зависимостей — более реалистичный фактор инцидентов, чем изощрённые атаки.