CSRF-защита

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


Механизм работы CSRF

CSRF-атака обычно использует доверие сайта к браузеру пользователя. Если пользователь вошёл в систему и имеет активную сессию (cookie), злоумышленник может заставить его браузер выполнить действия от его имени, например:

  • Изменение пароля или электронной почты.
  • Совершение покупки или перевода средств.
  • Выполнение административных команд.

Ключевой момент: браузер автоматически прикрепляет cookie сессии к каждому запросу, поэтому достаточно простого GET или POST запроса для успешной атаки.


Основные подходы к защите

  1. CSRF-токены Наиболее распространенный способ защиты. Сервер генерирует уникальный токен для каждой сессии или запроса, который клиент должен включить в форму или заголовок запроса.

    • Генерация токена: Токен создаётся на сервере и хранится в сессии пользователя.

      // Node.js пример генерации
      const crypto = require('crypto');
      function generateCSRFToken(session) {
          const token = crypto.randomBytes(32).toString('hex');
          session.csrfToken = token;
          return token;
      }
    • Включение в форму: В Slim.js компоненте форма может содержать скрытое поле с токеном:

      <form method="POST" action="/update-profile">
          <input type="hidden" name="csrfToken" value="{{csrfToken}}">
          <input type="text" name="username">
          <button type="submit">Сохранить</button>
      </form>
    • Проверка токена: На сервере при обработке запроса токен сравнивается с тем, что хранится в сессии:

      function verifyCSRFToken(session, token) {
          return token && session.csrfToken && token === session.csrfToken;
      }
  2. Защита через заголовки Для AJAX-запросов часто используют заголовок X-CSRF-Token. Slim.js позволяет легко интегрировать такой подход:

    fetch('/api/update', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'X-CSRF-Token': csrfToken
        },
        body: JSON.stringify({username: 'newName'})
    });
  3. SameSite для cookie Установка атрибута SameSite для cookies ограничивает отправку сессионного cookie только теми запросами, которые инициированы с того же сайта:

    res.cookie('sessionId', sessionId, { httpOnly: true, sameSite: 'Strict' });
    • Strict предотвращает отправку cookie в любых сторонних запросах.
    • Lax позволяет отправку при навигации, но блокирует автоматические POST-запросы.
  4. Двойная проверка токена (Double Submit Cookie) Токен одновременно хранится в cookie и передается в теле запроса. Сервер проверяет совпадение значений. Этот метод позволяет снизить нагрузку на серверную сессию.


Интеграция CSRF-защиты в Slim.js

Slim.js ориентирован на работу с компонентами и реактивными данными. CSRF-токен удобно хранить в состоянии компонента и автоматически внедрять его в формы и запросы:

import { component, html } from 'slim-js';

component('update-form', class extends HTMLElement {
    onBeforeMount() {
        this.state = { csrfToken: window.csrfToken };
    }

    onSubmit(e) {
        e.preventDefault();
        fetch('/api/update', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-CSRF-Token': this.state.csrfToken
            },
            body: JSON.stringify({ username: this.querySelector('#username').value })
        });
    }

    render() {
        return html`
            <form @submit=${this.onSubmit.bind(this)}>
                <input id="username" type="text" name="username">
                <button type="submit">Обновить</button>
            </form>
        `;
    }
});

Ключевой аспект: токен передается только через безопасный канал, и компоненты автоматически используют его при каждом запросе.


Рекомендации по безопасности

  • Использовать уникальные токены для каждой сессии или запроса.
  • Не передавать токены в URL — это снижает риск утечки через логи или рефералы.
  • Обновлять токен после успешного использования.
  • Совмещать CSRF-токены с SameSite и HttpOnly cookie для максимальной защиты.
  • Для API использовать проверку заголовков, а для форм — скрытые поля с токеном.

Отличия CSRF-защиты в SPA и традиционных формах

В SPA на Slim.js все взаимодействия обычно идут через fetch или XHR. Здесь критично:

  • Хранить токен в памяти приложения или безопасном cookie.
  • Подставлять токен автоматически во все POST/PUT/DELETE запросы.
  • В случае повторной аутентификации — обновлять токен в компонентах, чтобы старые значения не использовались.

Для традиционных HTML-форм токен внедряется в скрытые поля, и сервер проверяет их при каждом POST-запросе.


Систематическое внедрение этих методов обеспечивает надежную защиту от CSRF-атак в приложениях на Slim.js, сочетая безопасность с удобством работы компонентов и реактивного состояния.