Веб
Безопасность Laravel-проекта: 12 проверок перед экспертизой
APP_DEBUG, trustProxies, CSRF, mass assignment, политики, rate limiting и ещё 12 пунктов — практический список для подготовки Laravel-приложения к экспертизе.
· 9 мин. чтения

Laravel поставляется с хорошими настройками безопасности по умолчанию: защита от CSRF, хеширование паролей, шифрованные cookie. Но большая часть проблем, которые находит экспертиза, возникает не из-за самого фреймворка, а из-за его конфигурации. Ниже — 12 пунктов, которые мы проверяем в своих проектах и по опыту экспертиз. Примеры написаны для структуры Laravel 11/12.
1. APP_DEBUG и APP_ENV
В production в файле .env:
APP_ENV=production
APP_DEBUG=false
При APP_DEBUG=true на странице ошибки видны стек вызовов, пути к файлам, а иногда и переменные окружения. Для проверки отправьте запрос на несуществующий маршрут или с некорректным параметром и убедитесь, что в ответе нет внутренних деталей.
2. trustProxies и заголовок Host
Если приложение работает за Nginx или балансировщиком, прокси-заголовкам нужно доверять. Но не всем. В нашем собственном продукте экспертиза нашла внедрение через заголовок Host: приложение доверяло X-Forwarded-Host и могло формировать ссылки сброса пароля с доменом, указанным атакующим. Исправление — доверять только нужным заголовкам:
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
$middleware->trustProxies(at: '127.0.0.1', headers:
Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO);
})
Дополнительно в production задайте URL::forceRootUrl(config('app.url')) и URL::forceScheme('https') в AppServiceProvider.
3. Исключения CSRF
Защита CSRF включена по умолчанию, но со временем список validateCsrfTokens(except: [...]) разрастается. Пересмотрите каждое исключение: оно должно быть только для callback внешнего сервиса (например, платёжного провайдера), и на этом маршруте должна быть проверка подписи или другая проверка.
4. Mass assignment
$guarded = [] или Model::unguard() — тревожный признак. Если пользователь добавит в запрос is_admin=1 или balance=..., это может записаться в модель. Перечислите в $fillable только разрешённые поля и используйте $request->validated() вместо $request->all().
5. Авторизация: Policy и Gate
Аутентификация отвечает на вопрос «кто?», авторизация — «имеет ли он на это право?». Может ли пользователь, открывший /invoices/15, открыть и /invoices/16? Это называется IDOR (CWE-639). Напишите Policy для каждого ресурса и вызывайте в контроллере $this->authorize('view', $invoice) или Gate::authorize(). Списковые запросы тоже ограничивайте текущим пользователем или организацией.
6. Бизнес-логика и проверка состояния
На нашей платформе экспертиза зафиксировала две находки по бизнес-логике. Первая — страница «оплата прошла успешно» показывалась без подтверждения от платёжного провайдера. Правильный подход: менять статус платежа только через server-to-server callback провайдера или запрос к его API, а страница успеха должна показывать реальный статус из базы. Вторая — выполнение действия без проверки состояния. При каждом переходе (например, «черновик → отправлен») проверяйте текущее состояние на сервере.
7. Rate limiting
Поставьте ограничения на вход, сброс пароля, отправку OTP и поиск:
RateLimiter::for('login', function (Request $request) {
return Limit::perMinute(5)->by(
Str::lower($request->input('email')).'|'.$request->ip()
);
});
Добавьте маршруту ->middleware('throttle:login'). Для API-маршрутов задайте отдельный лимит.
8. Флаги сессионных cookie
config/session.php и .env:
SESSION_SECURE_COOKIE=true
SESSION_HTTP_ONLY=true
SESSION_SAME_SITE=lax
SESSION_ENCRYPT=true
Проверьте, что после входа вызывается $request->session()->regenerate(), а при выходе — invalidate() и regenerateToken(). Стартовые наборы Laravel это делают, но в самописных сценариях входа об этом часто забывают.
9. Аудит зависимостей
composer audit
npm audit --omit=dev
Если в результате есть пакеты с известными уязвимостями — обновите их. composer.lock должен быть в репозитории, а в production устанавливайте через composer install --no-dev --optimize-autoloader.
10. Подписанные URL
В ссылках подтверждения email, скачивания файла или отписки не оставляйте открытый ID. Используйте URL::temporarySignedRoute('invoice.download', now()->addMinutes(30), [...]) и middleware signed на маршруте. Тогда изменить ссылку и попасть к чужой записи не получится.
11. Раскрытие информации
В нашей экспертизе две находки были именно такого типа. Первая — через Ziggy в браузер передавался полный список маршрутов, включая административные. В config/ziggy.php выводите только нужные маршруты через only или groups. Вторая — лишние поля в ответах API. Вместо прямого возврата модели используйте API Resource и проверьте $hidden. Также уберите из заголовков X-Powered-By и версию сервера.
12. Загрузка файлов и открытые каталоги
- Проверяйте загружаемые файлы правилами
mimes,maxи по возможности храните их на закрытом диске, а не вpublic. - Корень веб-сервера — только
public/. Убедитесь, что.env,storage/logs,.gitне открываются из браузера. telescope,horizon,phpinfoи отладочные панели в production должны быть закрыты или доступны только администратору.
Хорошее правило: отмечайте каждый пункт не как «есть в коде», а как «проверил на практике».
Как проверять
Одного прочтения списка мало. Для каждого пункта сделайте конкретную проверку: запросите сброс пароля с curl -H "X-Forwarded-Host: example.org", откройте ресурс с чужим ID, введите неверный пароль 10 раз подряд. Записывайте результаты — именно эти записи понадобятся при подготовке ответа экспертизе.
Вывод
В Laravel безопасность часто зависит от одной строки настройки. Последовательный проход по 12 пунктам заранее закрывает значительную часть типичных находок экспертизы.
Sipar проверяет Laravel-проекты по этим и другим пунктам: ИИ-агент Claude просматривает код и конфигурацию, эксперт подтверждает находки и исправляет их. Чтобы проверить свой проект, оставьте заявку на сканирование.


