Передача токена через Cookie

Передача аутентификационного токена через cookie в связке с Iron строится вокруг идеи защищённого контейнера, в котором данные не просто подписываются, а полностью шифруются и проверяются на целостность. В отличие от классического подхода с JWT в открытом виде, здесь содержимое сессии недоступно клиенту и может быть восстановлено только сервером при наличии секретного ключа.

Роль Iron в защите данных

Библиотека Iron реализует механизм sealing/unsealing — упаковки данных в зашифрованную строку и последующего безопасного извлечения.

Основные свойства:

  • Конфиденциальность — содержимое токена шифруется
  • Целостность — любые изменения данных обнаруживаются при расшифровке
  • Привязка к секрету — без ключа восстановление невозможно

Фактически Iron превращает объект сессии в строку, пригодную для хранения в cookie, при этом исключая возможность подделки на стороне клиента.

Обычно токен представляет собой объект с минимально необходимыми данными:

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

Пример структуры:

const session = {
  userId: "u12345",
  role: "admin",
  createdAt: Date.now()
};

Перед сохранением в cookie этот объект проходит процедуру sealing:

import Iron from '@hapi/iron';

const password = process.env.COOKIE_SECRET;

const sealed = await Iron.seal(session, password, Iron.defaults);

Результат — строка, содержащая зашифрованный payload и контроль целостности.

После формирования sealed-значения оно отправляется клиенту через заголовок Set-Cookie.

Пример в Node.js (Express):

res.setHeader('Set-Cookie', `session=${sealed}; HttpOnly; Secure; SameSite=Strict; Path=/`);

Ключевые параметры cookie:

  • HttpOnly — запрет доступа через JavaScript
  • Secure — передача только по HTTPS
  • SameSite — защита от CSRF-атак
  • Path — ограничение области действия cookie

С точки зрения клиента cookie становится непрозрачным контейнером, который нельзя прочитать или модифицировать без потери валидности.

При каждом запросе сервер получает cookie и выполняет обратную операцию — unseal.

import Iron from '@hapi/iron';

const sealed = req.cookies.session;

const session = await Iron.unseal(sealed, password, Iron.defaults);

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

После восстановления объект сессии используется для авторизации пользователя:

req.user = session.userId;
req.role = session.role;

Важный аспект — синхронизация срока жизни cookie и логики сессии.

Cookie может управляться через:

  • Max-Age — абсолютное время жизни
  • Expires — дата истечения
  • серверное обновление при активности пользователя

Пример:

res.setHeader(
  'Set-Cookie',
  `session=${sealed}; Max-Age=3600; HttpOnly; Secure; SameSite=Strict`
);

Даже если sealed-данные корректны, истёкший cookie считается недействительным.

Обновление токена и ротация сессии

В системах с высокой нагрузкой применяется периодическая ротация sealed-токена:

  1. сервер расшифровывает текущую сессию
  2. обновляет временные поля
  3. создаёт новый sealed
  4. перезаписывает cookie
const session = await Iron.unseal(req.cookies.session, password, Iron.defaults);

session.lastActivity = Date.now();

const renewed = await Iron.seal(session, password, Iron.defaults);

res.setHeader('Set-Cookie', `session=${renewed}; HttpOnly; Secure; SameSite=Strict`);

Это позволяет ограничивать риск повторного использования старых токенов и снижает вероятность атак на основе перехвата.

Использование Iron не отменяет необходимость корректной конфигурации cookie. Основные угрозы и меры защиты:

Перехват трафика

  • решение: обязательный HTTPS + Secure cookie

XSS-атаки

  • решение: HttpOnly, минимизация клиентского JavaScript доступа

CSRF

  • решение: SameSite=Strict или SameSite=Lax + CSRF-токены

Подмена cookie

  • решение: невозможна без секретного ключа Iron

Утечка секретного ключа

  • решение: ротация ключей и хранение в защищённой среде (env/vault)

Разделение ответственности между клиентом и сервером

При использовании Iron в cookie клиентская сторона полностью лишена логики интерпретации токена. Вся модель выглядит как:

  • клиент хранит непрозрачную строку
  • сервер контролирует структуру данных
  • сервер управляет сроком жизни и обновлением

Это создаёт централизованную модель доверия, где cookie выступает только как транспорт.

Частые проблемы при внедрении:

Неверный secret

  • приводит к невозможности unseal

Смена конфигурации Iron

  • несовместимость форматов старых токенов

Отсутствие обработки исключений

  • ошибка расшифровки может приводить к падению middleware

Пример обработки:

try {
  const session = await Iron.unseal(cookie, password, Iron.defaults);
  req.user = session.userId;
} catch (err) {
  res.setHeader('Set-Cookie', 'session=; Max-Age=0');
}

Практика минимизации данных в токене

Несмотря на возможность хранения сложных объектов, в sealed-cookie рекомендуется помещать только минимальный набор данных:

  • идентификатор пользователя
  • роль
  • временные метки

Всё остальное подгружается из базы данных при необходимости. Это уменьшает:

  • размер cookie
  • нагрузку на шифрование
  • риск утечки чувствительных данных

Масштабирование подхода

В распределённых системах важно учитывать, что Iron не предполагает шаринг состояния между сервисами. Все узлы должны иметь доступ к одному и тому же secret.

При необходимости используется:

  • централизованное хранилище конфигурации
  • синхронизация ключей
  • стратегия ротации с обратной совместимостью

Даже при перехвате sealed-cookie злоумышленник не может:

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

Однако возможен replay-attack, если не предусмотрены:

  • временные ограничения
  • привязка к IP/UA (опционально)
  • короткий TTL сессии

Итоговая модель взаимодействия

Работа с Iron и cookie формирует замкнутый цикл:

  • создание сессионного объекта
  • sealing через секрет
  • передача через cookie
  • восстановление через unseal
  • обновление при необходимости
  • уничтожение через очистку cookie

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