Безопасность веб-сервисов на Laravel: как не слить данные
Популярность Laravel — это одновременно плюс и минус. Чем больше проектов на фреймворке, тем больше на него внимания со стороны злоумышленников. По статистике, большинство утечек данных происходит не из-за багов самого фреймворка, а из-за ошибок в настройке, устаревших пакетов и человеческого фактора.
Если ваш сервис хранит персональные данные, платежную информацию или корпоративные документы, безопасность — это база. Разбираем, где чаще всего возникают уязвимости в Laravel-приложениях и как их закрыть.
SQL-инъекции: почему Eloquent спасает, но не всегда
SQL-инъекция позволяет злоумышленнику выполнить произвольный код в базе данных. Результат — доступ ко всем таблицам, включая пароли и токены.
Laravel защищает от этого через Eloquent ORM и Query Builder. Они используют prepared statements (параметризованные запросы). Данные отделяются от SQL-команды, поэтому злоумышленник не может внедрить свой код.
php
// Безопасно: Eloquent автоматически экранирует параметры
$user = User::where('email', $request->email)->first();
// Опасно: конкатенация в raw-запросе
DB::select("SELECT * FROM users WHERE email = '" . $request->email . "'");
Проблема возникает, когда разработчики используют raw-запросы для сложных выборок. Если в такой запрос попадают данные от пользователя без параметризации, уязвимость появляется мгновенно.
Совет: используйте Eloquent или Query Builder везде, где возможно. Raw-запросы — только когда это необходимо, и всегда с параметризацией.
XSS-атаки: когда пользователь сам себе вредит
Cross-Site Scripting (XSS) — это вставка вредоносного JavaScript-кода на страницу. Код выполняется в браузере других пользователей, что позволяет красть сессии, перенаправлять на фишинговые страницы или воровать данные из форм.
Blade-шаблонизатор Laravel автоматически экранирует данные при выводе:
blade
{{-- Безопасно: данные экранируются автоматически --}}
{{ $user->name }}
{{-- Опасно: необработанный HTML --}}
{!! $comment !!}
Главный риск — использование {!! !!} для пользовательского контента. Если пользователь может вводить текст (комментарии, описания), этот контент нужно очищать через библиотеку типа HTMLPurifier перед выводом.
Совет: никогда не выводите пользовательский контент через {!! !!} без санитизации. Если нужен форматированный текст, используйте Markdown-парсер с whitelist-правилами.
CSRF: невидимые запросы от имени пользователя
Cross-Site Request Forgery (CSRF) — атака, при которой злоумышленник заставляет авторизованного пользователя выполнить действие на сайте без его ведома. Например, перевести деньги или изменить пароль.
Laravel автоматически защищает от CSRF через middleware. Все формы, созданные через Blade, получают CSRF-токен. Для AJAX-запросов токен передается в заголовке X-CSRF-TOKEN.
blade
<form method="POST">
@csrf
</form>
Риск возникает, когда разработчики отключают CSRF-защиту для API-маршрутов, не настроив правильную аутентификацию. Для API используйте Laravel Sanctum или Passport.
Совет: не отключайте CSRF-защиту без причины. Для API используйте Sanctum/Passport с правильными настройками guard.
Аутентификация и авторизация: типичные ошибки
Слабая аутентификация — одна из главных причин компрометации аккаунтов. Брутфорс, утечка токенов, слабые пароли.
Laravel предлагает несколько подходов:
-
Сессии и cookies — для классических веб-приложений. Встроенная система использует bcrypt для хеширования паролей.
-
Laravel Sanctum — для SPA и мобильных приложений. Управляет API-токенами с ограниченным сроком действия.
-
Laravel Passport — для полноценной OAuth2-аутентификации.
-
Laravel Jetstream / Breeze — готовые наборы с поддержкой двухфакторной аутентификации (2FA).
Частые ошибки:
Отсутствие 2FA. Для B2B-сервисов с корпоративными данными двухфакторная аутентификация — обязательный минимум.
Слабые пароли. Laravel позволяет проверять пароли через HaveIBeenPwned API, чтобы исключить скомпрометированные варианты:
php
use Illuminate\Validation\Rules\Password;
$validator = Validator::make($data, [
'password' => [
'required',
'confirmed',
Password::min(8)
->letters()
->mixedCase()
->numbers()
->symbols()
->uncompromised(),
],
]);
Отсутствие rate limiting. Без ограничения запросов на вход злоумышленник может перебирать пароли бесконечно.
php
Route::middleware('throttle:5,1')->group(function () {
Route::post('/login', 'AuthController@login');
});
Совет: включайте 2FA для корпоративных сервисов, настраивайте rate limiting на маршрутах входа и проверяйте пароли через HaveIBeenPwned.
Массовое присваивание: когда пользователь меняет свои роли
Mass Assignment — уязвимость, при которой злоумышленник отправляет запрос с дополнительными полями, которые не должны быть доступны для редактирования. Например, добавляет is_admin: true к своему профилю.
Laravel защищает через $fillable или $guarded в моделях:
php
class User extends Model
{
protected $fillable = ['name', 'email', 'phone'];
}
Только поля из $fillable могут быть массово присвоены через create() или update(). Поля вроде is_admin, role, balance в этот список не попадают.
Совет: всегда определяйте $fillable или $guarded для каждой модели. Никогда не используйте $guarded = [] — это отключает защиту полностью.
Шифрование данных и хранение секретов
Конфиденциальные данные должны храниться в зашифрованном виде, если это требует бизнес-логика или регуляторы.
Laravel предоставляет встроенное шифрование через encrypt() и decrypt(). Данные шифруются алгоритмом AES-256-CBC с ключами из .env файла.
php
$encrypted = encrypt($userData);
$decrypted = decrypt($encrypted);
Критически важно: .env файл никогда не должен попадать в систему контроля версий. Утечка .env — один из самых простых способов для злоумышленников получить доступ к базе данных и API-ключам.
Совет: храните секреты в .env, добавьте файл в .gitignore и регулярно ротируйте ключи приложения.
Rate limiting и защита API
Если ваш проект предоставляет API, защита от перебора и злоупотреблений обязательна. Laravel включает встроенный middleware для rate limiting.
php
// 100 запросов в минуту на API-маршруты
Route::middleware('throttle:100,1')->group(function () {
Route::apiResource('users', UserController::class);
});
В Laravel 11+ доступен новый fluent API для более гибкой настройки:
php
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(100)->by($request->user()?->id ?: $request->ip());
});
Совет: настраивайте rate limiting на всех публичных API-эндпоинтах. Для смены пароля или оплаты лимиты должны быть строже.
Обновления и зависимости
Laravel регулярно выпускает обновления, закрывающие уязвимости. За последние годы были исправлены:
CVE-2021-43617 — уязвимость загрузки исполняемых файлов;
CVE-2022-25838 — проблема с механизмом одноразовых кодов TOTP;
CVE-2018-6330 — SQL-инъекция в обработчике ошибок.
Обновляйте Laravel и зависимости регулярно. Используйте composer outdated для проверки пакетов.
Совет: перед обновлением проверяйте changelog и тестируйте приложение на staging-окружении. Автоматические тесты с покрытием от 90% помогут убедиться, что обновление не сломало бизнес-логику.
Настройка production-окружения
Многие уязвимости появляются из-за неправильной конфигурации сервера.
Отключите debug mode. Параметр APP_DEBUG=false скрывает детальную информацию об ошибках. Включённый debug mode в production раскрывает структуру проекта и SQL-запросы.
Настройте права доступа. Файлы конфигурации и логи должны быть доступны только пользователю веб-сервера. Права 640 на конфиги и 750 на директории — минимальный стандарт.
Используйте HTTPS. Все данные между клиентом и сервером должны шифроваться. Настройте SSL-сертификат и принудительный редирект HTTP → HTTPS.
Настройте Content Security Policy (CSP). Заголовок CSP ограничивает источники, откуда браузер может загружать скрипты. Это снижает риск XSS-атак.
Чек-лист безопасности перед запуском
Перед запуском в production проверьте список:
-
Laravel и зависимости обновлены до последних версий;
-
APP_DEBUG отключён;
-
.env файл в .gitignore, ключ приложения сгенерирован;
-
В моделях настроены $fillable или $guarded;
-
CSRF-защита включена;
-
Пользовательский контент экранируется через {{ }};
-
Rate limiting настроен на маршрутах входа и API;
-
2FA включена для корпоративных сервисов;
-
HTTPS включен, SSL-сертификат действителен;
-
Настроен CSP-заголовок;
-
Права доступа к файлам ограничены;
-
Логи не содержат конфиденциальных данных.
Итоги
Безопасность Laravel-приложения — это совокупность практик на каждом уровне: от валидации данных до конфигурации сервера. Фреймворк предоставляет мощные встроенные средства защиты, но они работают только при правильном использовании.
Команда MACHAON закладывает безопасность на этапе проектирования архитектуры. Это означает строгую валидацию данных, настройку авторизации через Policies и Gates, покрытие критических маршрутов тестами и регулярный аудит зависимостей.
Если ваш веб-сервис работает с чувствительными данными, не ждите инцидента. Профилактика всегда дешевле, чем устранение последствий утечки.