Уявіть: ваш сайт використовує сесійні куки, і користувач, будучи авторизованим, переходить за посиланням на зловмисний сайт. Той надсилає 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-токена.







