Как работают механизмы защиты от Csrf в Spa и как обезопасить приложение

Почему CSRF до сих пор опасен для SPA

CSRF‑атака выглядит почти невинно: пользователь авторизован в браузере, злоумышленник подсовывает ему ссылку или невидимую форму, браузер сам добавляет cookies авторизации — и на сервер уходит «легальный» запрос. Для классических сайтов это давно известная проблема, но защита от csrf в веб приложениях с архитектурой SPA усложняется тем, что логика переносится в JavaScript, а API часто живёт на отдельном домене. В результате многие разработчики расслабляются, считая, что «у нас же токены в заголовках, всё ок», и пропускают типичные комбинации CSRF с XSS, уязвимыми CORS‑настройками и слабой валидацией происхождения запросов.

Базовый сценарий CSRF: текстовая диаграмма

Полезно разложить атаку по шагам, в формате простой текстовой диаграммы. Типичный сценарий выглядит так:

Пользователь авторизуется на сайте:
— Браузер ⇨ Сервер: POST /login + пароль
— Сервер ⇨ Браузер: Set-Cookie: session=abc…

Дальше атакующий действует:
— Пользователь открывает вредоносную страницу
— Вредоносный сайт встраивает форму или скрипт:
— Браузер ⇨ Сервер (жертвы): POST /transfer?to=attacker&sum=100
— Браузер автоматически добавляет Cookie: session=abc…
— Сервер видит валидную сессию и выполняет действие

Диаграмма потока:
Пользователь →[логин]→ Сервер →[cookie сессии]→ Браузер
Пользователь →[открыл сайт злоумышленника]→ Вредоносный сайт →[подсовывает форму]→ Браузер →[запрос с cookie]→ Сервер.

CSRF в контексте SPA: где тонко

SPA добавляет свои нюансы. Клиентское приложение на React, Vue или Angular часто общается с backend‑API по REST или GraphQL, использует JWT, session cookies и CORS. На первый взгляд кажется, что JSON‑API «менее уязвим», но браузер по‑прежнему автоматически шлёт cookies к домену API, даже если запрос инициирован чужим сайтом, а это основной триггер CSRF. Кроме того, SPA часто держат состояние авторизации в памяти и localStorage, забывая про ограничения для чувствительных токенов. Безопасность SPA приложений, защита от атак CSRF и их сочетаний с XSS напрямую зависит от того, насколько последовательно вы разделяете доверенные источники запросов и правильно управляете сессионными данными.

Csrf‑токен: что это и как использовать

Если говорить по‑простому, CSRF‑токен — это одноразовый «жетон‑подтверждение намерения», который должен присутствовать в каждом запросе, изменяющем состояние. Отсюда популярный вопрос: csrf токен что это и как использовать его в SPA? Сервер генерирует случайную строку, привязывает её к сессии и ожидает увидеть этот токен в теле или заголовке POST/PUT/DELETE‑запросов. В отличие от cookie, которые браузер прикрепляет автоматически, токен должен быть добавлен именно JavaScript‑кодом вашего приложения. Если атакующий просто заставит браузер отправить форму с чужого сайта, у него не будет корректного токена, и сервер отклонит запрос, тем самым разрывая типичный CSRF‑сценарий.

Текстовая схема проверки CSRF‑токена

Как работают механизми защиты от CSRF в SPA - иллюстрация

С точки зрения сервера всё выглядит примерно так:

1) Авторизация:
Браузер → Сервер: POST /login
Сервер:
— создаёт сессию: session=abc
— генерирует csrf=xyz
— отвечает: Set-Cookie: session=abc; HttpOnly
+ JSON: {«csrfToken»: «xyz»}

2) Запрос изменения:
SPA → Сервер: POST /profile/update
Заголовки:
— Cookie: session=abc
— X-CSRF-Token: xyz

Сервер проверяет: есть ли сессия, совпадает ли токен в заголовке с сохранённым значением. Если нет — 403 Forbidden. Эта логика одинаково важна и для REST, и для GraphQL‑эндпоинтов, даже если они используются только фронтендом SPA.

CSRF и session cookies против JWT: сравнение подходов

Многие надеются, что переход на JWT «сам по себе» решает CSRF, потому что токен не лежит в cookie. Но если JWT хранится в cookie (что делают ради безопасности от XSS) и автоматически отправляется браузером, CSRF возвращается. Если же JWT хранится в localStorage и передаётся через Authorization‑заголовок, атака через простой

уже затруднена, но XSS мгновенно превращает её обратно в CSRF‑подобный сценарий. Поэтому вместо упрощённого противопоставления «cookies vs JWT» имеет смысл рассматривать совокупность: где хранится токен, как он передаётся, какие origin имеют доступ и какие CSRF‑механизмы включены на уровне API.

Double Submit Cookie и SameSite: текстовые диаграммы

Помимо классического server‑side CSRF‑токена есть подход double submit cookie. Сервер ставит csrf‑cookie, а фронтенд SPA читает его и отправляет токен в заголовке. Диаграмма:

Сервер → Браузер: Set-Cookie: csrf=xyz; SameSite=Lax
SPA → Сервер: POST /action
Заголовки: Cookie: session=abc; csrf=xyz
+ X-CSRF-Token: xyz

Сервер сравнивает значение из cookie и заголовка. Вредоносный сайт не может выставить правильный заголовок, а cookie контролирует только ваш домен. Дополнительно атрибут SameSite=Lax/Strict уменьшает вероятность того, что cookies передадутся на кросс‑сайт формы, делая защиту от csrf в веб приложениях более многослойной, а не опирающейся на один отдельный механизм.

Практическая настройка защиты в популярных фреймворках

Когда речь заходит про настройку защиты от csrf в react vue angular, важно помнить: сами по себе эти фреймворки не «делают безопасность». Они лишь помогают удобно вкручивать механизмы, реализованные на backend‑стороне. Типовый подход: backend (Django, Spring, Laravel, NestJS и т.д.) отдаёт SPA и параллельно выдаёт CSRF‑токен через cookie или JSON, а фронтенд‑приложение оборачивает все запросы в централизованный HTTP‑клиент (axios, fetch wrapper), который автоматически подставляет токен в заголовок. Эксперты рекомендуют не разбрасывать прямые fetch‑вызовы по коду, а держать единую точку, где включены все политики безопасности.

Рекомендации по внедрению CSRF‑защиты в SPA

Опытные разработчики обычно придерживаются нескольких принципов:

— Централизовать HTTP‑клиент и вешать туда добавление CSRF‑заголовков.
— Включить SameSite для сессионных cookies и CSRF‑cookies.
— Разделять домены: SPA может жить на app.example.com, а API — на api.example.com, но CORS должен быть строго настроен.
— Ограничивать методы и заголовки, разрешённые через CORS, чтобы уменьшить поверхность атаки.
— В логике backend явно различать безопасные (GET) и модифицирующие (POST/PUT/PATCH/DELETE) запросы и требовать токен только на втором типе.

Типичные ошибки и анти‑паттерны

На практике защита ломается не из‑за отсутствия инструментов, а из‑за мелких компромиссов. Например, отключают CSRF‑проверку «на время» для тестов и забывают включить обратно, выставляют CORS с wildcard‑origins для «удобства фронтенда», начинают передавать чувствительные токены через query‑параметры. Ещё один популярный анти‑паттерн — полагаться исключительно на SameSite, считая, что это «магическая защита от всего». Эксперты по безопасности подчёркивают: SameSite уменьшает риск, но не отменяет необходимость в серверной проверке токена, строгой валидации заголовков Origin/Referer и периодическом обновлении сессионных ключей.

Экспертные советы по архитектуре и аудитам

Как работают механизми защиты от CSRF в SPA - иллюстрация

Если проект бизнес‑критичный, имеет смысл периодически привлекать внешние услуги по защите сайта от csrf и хакерских атак. Пентестеры и специалисты по AppSec пытаются воспроизвести реальные сценарии: комбинируют CSRF с XSS, проверяют обход SameSite, раскачивают CORS‑политику и ищут забытые эндпоинты без проверки токена. Полезный приём — threat modeling: совместно с разработчиками и безопасниками прорисовать диаграмму потоков данных: кто инициирует запросы, какие cookies при этом отправляются, где происходит проверка токена и что будет, если злоумышленник контролирует любой из этих узлов. Такой подход помогает увидеть сбои в логике раньше, чем ими воспользуются реальные атакующие.

Что стоит внедрить в ближайший спринт

Если резюмировать рекомендации экспертов для SPA‑команд, минимальный набор действий выглядит так:

— Включить CSRF‑механизм на backend и убедиться, что SPA получает и передаёт токен в каждом изменяющем запросе.
— Пересмотреть CORS‑настройки, сузить список доверенных origin до реально используемых фронтов.
— Включить SameSite и Secure для cookies, хранить чувствительные токены в HttpOnly‑cookies.
— Добавить unit и e2e‑тесты, которые эмулируют запросы без токена и проверяют, что сервер корректно их режет.

Такая базовая дисциплина не потребует кардинальной переработки кода, зато существенно повысит безопасность SPA приложений, защиту от атак CSRF и создаст основу для дальнейшего укрепления защитного контура.