Валидация для предотвращения CSRF

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

Основная проблема CSRF не в отсутствии аутентификации, а в отсутствии проверки контекста запроса: сервер не различает легитимное действие пользователя и подделанный запрос, если тот проходит базовую аутентификацию.

Валидация в таких сценариях становится не просто проверкой форматов данных, а механизмом контроля целостности запроса, включая происхождение, токены и структуру передаваемых параметров.


Роль валидации в защите от CSRF

В системах, где используется сессионная аутентификация, защита от CSRF строится на нескольких уровнях:

  • проверка CSRF-токена
  • проверка заголовков Origin и Referer
  • контроль структуры запросов
  • валидация параметров формы и тела запроса

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


CSRF-токен как объект валидации

CSRF-токен представляет собой криптографически случайную строку, которая:

  • генерируется на сервере
  • связывается с пользовательской сессией
  • передаётся клиенту
  • возвращается в каждом опасном запросе (POST, PUT, DELETE)

С точки зрения валидации токен рассматривается как обязательное поле с жёсткими требованиями:

  • тип: строка
  • длина: фиксированная или в диапазоне (например, 32–128 символов)
  • набор символов: base64url или hex
  • обязательность: всегда присутствует

Проверка CSRF-токена с использованием Validator.js

Validator.js предоставляет набор функций для проверки строк, чисел и форматов, которые применяются для первичной фильтрации входных данных перед сравнением токенов на сервере.

Пример базовой проверки структуры токена:

import validator from "validator";

function validateCsrfToken(token) {
  if (!validator.isString(token)) return false;
  if (!validator.isLength(token, { min: 32, max: 128 })) return false;
  if (!validator.isAlphanumeric(token)) return false;

  return true;
}

Хотя CSRF-токены часто содержат символы вне алфавитно-цифрового набора (например, base64url), валидация может быть адаптирована под конкретный формат:

function validateCsrfToken(token) {
  const base64UrlRegex = /^[A-Za-z0-9\-_]+$/;
  return (
    typeof token === "string" &&
    token.length === 64 &&
    base64UrlRegex.test(token)
  );
}

Сравнение токенов: валидация vs проверка целостности

Важно различать два этапа:

1. Структурная валидация

Проверяется:

  • тип данных
  • длина
  • допустимые символы

2. Криптографическая проверка

Проверяется:

  • совпадение с серверным значением
  • принадлежность сессии
  • срок действия

Validator.js используется только на первом этапе, исключая мусорные или потенциально вредоносные значения до выполнения дорогостоящих операций сравнения.


Валидация заголовков Origin и Referer

CSRF-защита часто дополняется проверкой заголовков:

  • Origin: основной источник запроса
  • Referer: URL страницы-источника

С точки зрения валидации применяются правила:

  • проверка наличия значения
  • проверка формата URL
  • проверка соответствия доверенному домену

Пример:

import validator from "validator";

const trustedOrigins = ["https://example.com"];

function validateOrigin(origin) {
  if (!validator.isURL(origin)) return false;
  return trustedOrigins.includes(origin);
}

Такая проверка не является полной защитой, но значительно снижает риск выполнения запросов с внешних доменов.


Валидация структуры CSRF-защищённых запросов

CSRF-защищённые эндпоинты требуют строгой структуры тела запроса. Например:

{
  "amount": 1000,
  "recipientId": "12345",
  "csrfToken": "abc123..."
}

Каждое поле проходит независимую проверку:

  • amount: число в допустимом диапазоне
  • recipientId: идентификатор фиксированного формата
  • csrfToken: строка с жёсткими ограничениями

Пример комплексной валидации:

import validator from "validator";

function validateTransferBody(body) {
  const { amount, recipientId, csrfToken } = body;

  if (!validator.isInt(String(amount), { min: 1, max: 100000 })) {
    return false;
  }

  if (!validator.isNumeric(recipientId)) {
    return false;
  }

  if (!validateCsrfToken(csrfToken)) {
    return false;
  }

  return true;
}

Интеграция с серверным фреймворком

В контексте Express валидация CSRF-защищённых запросов часто реализуется как middleware.

import validator from "validator";

function csrfMiddleware(req, res, next) {
  const tokenFromBody = req.body.csrfToken;
  const tokenFromSession = req.session.csrfToken;

  if (!validateCsrfToken(tokenFromBody)) {
    return res.status(400).send("Invalid token format");
  }

  if (tokenFromBody !== tokenFromSession) {
    return res.status(403).send("CSRF validation failed");
  }

  next();
}

Такое разделение позволяет отделить синтаксическую проверку (через Validator.js) от логической проверки безопасности.


Ограничения валидации при защите от CSRF

Валидация сама по себе не является механизмом защиты от CSRF, поскольку:

  • не предотвращает автоматическую отправку cookies браузером
  • не проверяет контекст пользовательского действия
  • не блокирует поддельные запросы при наличии валидного токена

Однако она критически важна как фильтр первого уровня:

  • исключает malformed input
  • предотвращает атаки через инъекции в токен
  • снижает риск обхода логики проверки

Ошибки проектирования при работе с CSRF и валидацией

На практике встречаются типовые ошибки:

Отсутствие проверки формата токена

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

Использование слабых правил валидации

Разрешение любых строк без ограничения длины увеличивает поверхность атаки.

Смешивание уровней ответственности

Когда Validator.js используется одновременно для:

  • проверки бизнес-логики
  • криптографической проверки
  • авторизационных решений

такое смешение усложняет аудит безопасности.


Валидация как часть многоуровневой защиты

CSRF-защита строится не на одном механизме, а на комбинации:

  • токены синхронизации
  • проверка заголовков
  • строгая валидация входных данных
  • контроль сессий

Validator.js занимает в этой архитектуре роль предфильтра, который обеспечивает корректность и предсказуемость данных до применения критических проверок безопасности.


Практика построения безопасной схемы обработки запросов

Типовой порядок обработки CSRF-защищённого запроса:

  1. Парсинг тела запроса
  2. Валидация структуры данных (Validator.js)
  3. Проверка формата CSRF-токена
  4. Сравнение с серверным токеном
  5. Проверка Origin/Referer
  6. Выполнение бизнес-логики

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


Значение строгой типизации входных данных

Даже в динамически типизированной среде JavaScript строгая валидация выполняет роль псевдотипизации:

  • предотвращает неявные преобразования
  • фиксирует контракт API
  • делает поведение системы предсказуемым

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