CSRF и методы защиты

CSRF (Cross-Site Request Forgery) — это тип уязвимости, при котором злоумышленник вынуждает пользователя выполнить нежелательное действие на веб-приложении, в котором тот аутентифицирован. В отличие от XSS, CSRF использует доверие приложения к пользователю, а не доверие пользователя к приложению.

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

Ключевая опасность заключается в том, что сервер доверяет cookies или токенам сессии, автоматически прикрепляемым браузером к запросам. Если не применяются меры защиты, злоумышленник может изменить данные пользователя, провести финансовые транзакции или изменить настройки аккаунта.


Основные методы защиты от CSRF

1. Использование CSRF-токенов

CSRF-токен — уникальное значение, генерируемое сервером для каждой сессии или формы. Оно включается в HTML-форму и проверяется сервером при получении запроса.

Принцип работы:

  • Сервер генерирует токен и передаёт его клиенту (в форме или заголовке).
  • При отправке формы токен возвращается серверу.
  • Сервер проверяет соответствие токена ожидаемому значению.

Особенности реализации в SPA:

  • В приложениях на Riot.js токен можно хранить в состоянии компонента или передавать через глобальный store.
  • При отправке запросов через fetch или axios токен включается в заголовок, например X-CSRF-Token.
// Пример отправки запроса с CSRF-токеном
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');

fetch('/api/update', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-Token': csrfToken
  },
  body: JSON.stringify({ data: 'новое значение' })
});

2. Проверка происхождения запроса (Origin и Referer)

Сервер может проверять заголовки Origin и Referer для POST-запросов.

  • Origin сообщает домен, с которого пришёл запрос.
  • Referer указывает полный URL страницы, откуда был инициирован запрос.

Пример проверки на сервере:

const validOrigins = ['https://example.com'];
if (!validOrigins.includes(req.headers.origin)) {
  res.status(403).send('Forbidden: invalid origin');
}

Эта защита работает только для современных браузеров, поддерживающих заголовки, и подходит для запросов с CORS.


Флаги SameSite и HttpOnly помогают ограничить риск CSRF:

  • SameSite=Strict или Lax предотвращает отправку cookies при межсайтовых запросах.
  • HttpOnly предотвращает доступ к cookie через JavaScript, но не защищает от CSRF напрямую — больше от XSS.

Пример настройки cookie:

res.cookie('session', sessionId, { httpOnly: true, sameSite: 'Strict' });

4. Принцип idempotent и безопасные методы

Запросы, которые изменяют состояние на сервере, должны использовать методы POST, PUT, DELETE. GET-запросы должны оставаться идемпотентными и не изменять данные. Это ограничивает возможности CSRF-атак, так как браузеры автоматически не отправляют кросс-доменные POST-запросы без пользовательского взаимодействия.


Практическая интеграция CSRF-защиты в Riot.js

В приложениях Riot.js рекомендуется:

  1. Хранить CSRF-токен в корневом компоненте или глобальном хранилище.
  2. Автоматически добавлять токен в каждый POST/PUT/DELETE-запрос через обёртку для fetch или кастомный store-метод.
  3. Обновлять токен при каждом изменении сессии или перезагрузке страницы.
// Глобальная функция для POST-запросов с токеном
export function postWithCSRF(url, data) {
  const token = window.csrfToken;
  return fetch(url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-CSRF-Token': token
    },
    body: JSON.stringify(data)
  });
}

Использование этих практик снижает риск CSRF-атак до минимума и обеспечивает безопасное взаимодействие компонентов Riot.js с сервером.


Рекомендации по архитектуре

  • Разделение клиентской и серверной логики с явным управлением сессией и токенами.
  • Применение CORS и строгих правил SameSite для cookies.
  • Единая точка генерации и проверки CSRF-токена на сервере.
  • Логирование подозрительных запросов с невалидными токенами или заголовками.

Эти меры позволяют создавать безопасные, масштабируемые приложения на Riot.js, минимизируя уязвимость к CSRF.