Глава 5.4: Работа с CSRF-токенами
Время изучения: 30 минут
1. Что такое CSRF-атака? "Угон" вашего корабля
Представьте, что вы залогинены в панели управления вашим космическим флотом (space-api.test
). В соседней вкладке вы открываете безобидный сайт с котиками (evil-cats.com
). На этом сайте есть скрытая форма, которая автоматически отправляет запрос на ваш сайт по адресу POST /api/planets/1/delete
.
Поскольку вы уже авторизованы на space-api.test
, ваш браузер любезно прикрепит к этому запросу все ваши cookies. Сервер Laravel увидит валидную сессию и подумает, что это вы сами решили списать планету. Планета будет удалена без вашего ведома.
Это и есть CSRF (Cross-Site Request Forgery) — атака, при которой злоумышленник заставляет браузер аутентифицированного пользователя выполнить нежелательное действие на доверенном сайте.
💡 Космическая аналогия:
Вы — капитан корабля, и у вас есть ключ-карта (сессия/cookie). Злоумышленник не может украсть вашу карту. Но он может обманом заставить вас приложить ее к терминалу списания ресурсов, пока вы отвлеклись. CSRF-токен — это как пин-код, который нужно ввести вместе с картой. Злоумышленник не знает пин-код, и его атака проваливается.
2. Как Laravel защищает от CSRF?
Laravel по умолчанию защищает все "небезопасные" веб-запросы (POST, PUT, PATCH, DELETE) с помощью CSRF-токена.
- При генерации страницы Laravel создает уникальный, случайный токен для сессии пользователя.
- Этот токен встраивается в HTML-формы.
- При отправке формы токен уходит вместе с запросом.
- На сервере middleware
VerifyCsrfToken
сравнивает токен из запроса с токеном, хранящимся в сессии. - Если токены не совпадают, Laravel прерывает запрос с ошибкой 419 (Session Expired/Page Expired).
Важно: API-маршруты в routes/api.php
не защищены CSRF, так как они предполагают другой механизм аутентификации (например, токены Sanctum), а не сессии на основе cookies. Наша текущая проблема касается именно веб-маршрутов и страниц, которые мы создаем в routes/web.php
.
3. Использование CSRF-токена в HTML-формах
Это самый простой сценарий. Laravel предоставляет для этого специальную Blade-директиву.
Пример: Форма для создания планеты
Создадим простую форму в файле resources/views/planets/create.blade.php
:
<h2>Форма запуска новой планеты</h2>
<form action="/planets" method="POST">
@csrf {{-- Вот она, магия! --}}
<label for="name">Название:</label>
<input type="text" id="name" name="name" required>
<label for="solar_system">Солнечная система:</label>
<input type="text" id="solar_system" name="solar_system" required>
{{-- ... другие поля ... --}}
<button type="submit">Запустить</button>
</form>
Директива @csrf
автоматически сгенерирует скрытое поле в форме:
Этого достаточно для защиты стандартных HTML-форм.
4. Использование CSRF-токена в AJAX/Fetch запросах
В прошлой главе мы отправляли DELETE
запрос с помощью JavaScript. Сейчас Laravel будет его блокировать с ошибкой 419. Нам нужно добавить CSRF-токен в заголовки нашего Fetch-запроса.
Шаг 1: Сделать токен доступным для JavaScript
Добавьте мета-тег с токеном в <head>
вашего мастер-макета resources/views/app.blade.php
. Это стандартная практика в Laravel.
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{{-- Добавляем CSRF-токен в мета-тег --}}
<meta name="csrf-token" content="{{ csrf_token() }}">
{{-- ... --}}
</head>
Функция csrf_token()
возвращает текущий токен.
Шаг 2: Модифицируем JavaScript для отправки токена
Теперь в нашем public/js/planets.js
мы можем прочитать этот токен и добавить его в заголовки всех "небезопасных" запросов.
// ... в файле public/js/planets.js ...
document.addEventListener('DOMContentLoaded', () => {
// Получаем токен из мета-тега
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
const deleteButtons = document.querySelectorAll('.delete-btn');
deleteButtons.forEach(button => {
button.addEventListener('click', async (event) => {
// ... логика подтверждения ...
try {
const response = await fetch(apiUrl, {
method: 'DELETE',
headers: {
'Accept': 'application/json',
'X-CSRF-TOKEN': csrfToken // <-- Добавляем токен в заголовки!
}
});
// ... остальная логика обработки ответа ...
} catch (error) {
// ...
}
});
});
});
- Имя заголовка
X-CSRF-TOKEN
— это стандарт, который Laravel проверяет по умолчанию.
Теперь наши AJAX-запросы тоже защищены. Попробуйте снова удалить планету — на этот раз запрос пройдет успешно.
Квиз для закрепления
🚀 Итог главы:
Вы установили "систему распознавания свой-чужой" на ваш космический корабль, защитив его от атак CSRF. Вы научились:
- Понимать суть и опасность CSRF-атак.
- Защищать стандартные HTML-формы с помощью директивы
@csrf
. - Передавать CSRF-токен в JavaScript через мета-тег.
- Включать токен в заголовки AJAX/Fetch запросов для их успешного выполнения.
Ваши веб-интерфейсы теперь не только интерактивны, но и безопасны. В следующей главе мы завершим создание нашего веб-интерфейса, рассмотрев, как правильно организовать маршрутизацию для веб-страниц.