Представьте: ваш сайт использует сессионные куки, и пользователь, будучи авторизованным, переходит по ссылке на злонамеренный сайт. Тот отправляет POST-запрос на изменение пароля — и без CSRF-токенов запрос проходит. Эта уязвимость входит в OWASP Top 10, и по статистике до 70% legacy-проектов не имеют никакой защиты. Мы часто встречаем эту боль на проектах, где защита либо отсутствует, либо реализована непоследовательно. Наша задача — навсегда закрыть эту уязвимость под ключ, с гарантией и документацией.
Проблемы, которые решаем
- Сессионные cookies автоматически прикрепляются браузером — злоумышленнику достаточно подсунуть жертве форму на своём домене. До 70% сайтов на устаревших фреймворках (например, PHP без фреймворка) не имеют никакой защиты.
- Некорректная настройка SameSite cookies — многие разработчики ставят
Noneради удобства, открывая дорогу CSRF. Мы фиксируем это и выбираем междуLaxиStrictс учётом UX. - Забывают про AJAX-запросы — SPA-приложения уязвимы, если не передавать CSRF-токен в заголовках. Мы настраиваем автоматическую передачу для Axios, Fetch, jQuery.
Как мы это делаем: кейс настройки Laravel Sanctum для SPA
Рассмотрим типичный проект: React-фронтенд на Next.js, бэкенд на Laravel с Sanctum. Клиент жалуется на ошибки 419 при отправке форм. Проблема: Sanctum использует паттерн Double Submit Cookie, но фронтенд не читал cookie XSRF-TOKEN.
Решение:
- В Laravel
config/sanctum.phpуказываем'stateful'с доменами клиентов. - На фронтенде устанавливаем
axios.defaults.withCredentials = true. - Читаем XSRF-TOKEN из cookie и передаём в заголовок X-XSRF-TOKEN:
// Axios interceptor axios.interceptors.request.use(config => { const token = document.cookie .split('; ') .find(row => row.startsWith('XSRF-TOKEN=')) ?.split('=')[1]; if (token) { config.headers['X-XSRF-TOKEN'] = token; } return config; }); Результат — 419 исчезли, безопасность обеспечена. Весь процесс занял 2 дня, включая тестирование.
Процесс работы
- Аналитика — аудит текущей архитектуры: сессионная или токен-аутентификация, какие формы и API-эндпоинты защищать.
- Проектирование — выбор методов: CSRF-токены, SameSite, Double Submit или комбинация. Определение исключений (webhooks).
- Реализация — внедрение на бэкенде (middleware, генерация токенов) и фронтенде (глобальные настройки HTTP-клиента).
- Тестирование — создание вредоносной страницы, проверка блокировки запросов, автоматизированные тесты.
- Деплой — развёртывание на staging, проверка, мониторинг ошибок 419/403.
Что входит в настройку под ключ
- Интеграция CSRF-защиты во все мутирующие запросы (POST, PUT, DELETE).
- Настройка SameSite cookies с оптимальным значением.
- Обработка исключений (Stripe, GitHub webhooks) с альтернативной верификацией.
- Поддержка SPA (Sanctum, JWT) и классических форм.
- Документация по эксплуатации и обучение команды.
- Месяц послепусковой поддержки.
Сроки ориентировочно
| Тип задачи | Срок |
|---|---|
| Базовая настройка на Laravel/Django/Rails | 1 день |
| Интеграция с существующим SPA (Sanctum/XSRF) | 1–2 дня |
| Аудит и исправление legacy-проекта | 2–5 дней |
Стоимость рассчитывается индивидуально под ваш стек и объём. Оценим проект за 1 день — свяжитесь для консультации.
Как выбрать между SameSite=Lax и Strict?
SameSite=Strict не отправляет cookie ни при каких кросс-сайтовых запросах — это безопасно, но ломает переходы с внешних ссылок (например, из email). SameSite=Lax разрешает отправку при GET-переходах, блокируя POST, что является компромиссом.
| Значение | Безопасность | UX |
|---|---|---|
Strict |
99% | Ломает переходы |
Lax |
95% | Сохраняет UX |
Наш опыт (более десяти лет внедрения) показывает, что Lax — выбор для 80% проектов. Если важен максимальный уровень, используем Strict с fallback-страницей для внешних ссылок.
Как защитить AJAX-запросы от CSRF?
Типичная ошибка: токен не обновляется после логина или истекает раньше сессии. Проверьте:
- Мета-тег генерируется в Blade (или аналоге) при загрузке страницы.
- Для SPA токен должен обновляться через cookie XSRF-TOKEN (Sanctum) или отдельный эндпоинт.
- Если используете
@csrfв формах, убедитесь, что они не кешируются.
Детальный пример: настройка для React + Laravel
В компоненте React добавьте использование хука useEffect для чтения и установки токена:
import axios from 'axios'; function App() { useEffect(() => { axios.get('/sanctum/csrf-cookie').then(() => { // токен уже в cookie XSRF-TOKEN }); }, []); const handleSubmit = async () => { await axios.post('/api/form', data); }; } Убедитесь, что сервер отправляет заголовок Set-Cookie: XSRF-TOKEN=...; SameSite=Lax.
Дополнительная проверка Origin/Referer
Даже с токенами мы добавляем проверку заголовка Origin на уровне middleware. Это defence-in-depth — если токен утек, атакующий не сможет подменить Origin.
public function handle($request, Closure $next) { $origin = $request->header('Origin'); if ($request->isMethod('POST') && $origin && !in_array($origin, $allowed)) { abort(403, 'Forbidden origin'); } return $next($request); } Почему комбинация методов надёжнее одного?
По статистике, сайты с одной лишь SameSite-защитой уязвимы в 5% случаев (атаки через поддомены). Токены закрывают эти 5%. Комбинируя оба подхода, мы гарантируем защиту на уровне OWASP Top 10. Закажите аудит безопасности вашего сайта — мы найдём и устраним CSRF-уязвимости за 1 день. Получите консультацию по выбору оптимальной стратегии защиты.
Чек-лист типичных ошибок при настройке
- Использование
SameSite=Noneбез HTTPS — cookie не будет отправляться. - Забывают обновлять токен после смены пароля или выхода.
- Исключают из проверки не только GET, но и HEAD запросы (должны быть безопасными).
- Не проверяют заголовок
Originпри наличии CSRF-токена.







