EnglishРусский Map

Аутентификация по сессионным cookie

title
Аутентификация по сессионным cookie
type
concept
summary
Стандартный паттерн сессий в браузере: непрозрачный случайный ID в HttpOnly cookie и сопоставление с состоянием пользователя на сервере
tags
authentication, security, web
created
2026-04-25
updated
2026-04-25
lang
ru
translation_of
cookie-session-auth
source_updated
2026-04-25
translated
2026-09-01
translator
lllm/antigravity/gemini-3.7-flash-medium

Стандартный паттерн для сохранения авторизации пользователей в браузере. После успешного входа сервер генерирует длинный случайный непрозрачный идентификатор сессии, сохраняет его в хранилище на стороне сервера с привязкой к пользователю и метаданным сессии (CSRF-токен, метка последней активности, IP, user-agent, роль) и возвращает в браузер через заголовок Set-Cookie. Браузер отправляет эту cookie с каждым последующим запросом к тому же origin; сервер находит запись сессии при каждом обращении.

Именно это имеют в виду gist от samsch и множество похожих материалов, когда советуют "использовать сессии вместо JWT". Это не ново, в этом нет ничего захватывающего, и это работает.

Значение cookie - это просто идентификатор сессии: непрозрачная случайная строка с достаточной энтропией, чтобы её нельзя было угадать (обычно 128+ бит в кодировке base64). Она не содержит данных пользователя. Все данные пользователя живут на стороне сервера под этим ключом, поэтому отзыв, ротация и обновление тривиальны: изменили строку в базе - следующий запрос уже видит изменения.

  • HttpOnly - JavaScript не может прочитать cookie. Это нейтрализует кражу сессий через XSS.
  • Secure - cookie передаётся только по HTTPS. Обязательно в любой современной конфигурации.
  • SameSite=Lax (или Strict) - блокирует межсайтовый CSRF в большинстве типичных случаев. Lax - современный вариант по умолчанию; Strict надёжнее, но ломает переходы по ссылкам со сторонних сайтов в залогиненном состоянии.
  • Path и Domain - ограничивают область действия cookie там, где она нужна. По умолчанию стоит выбирать наиболее строгие работающие значения.
  • Max-Age / Expires - управляют временем жизни cookie в браузере. Сервер также должен независимо отслеживать и ограничивать срок действия сессии.

Что хранится в серверном хранилище сессий

  • Идентификатор пользователя и снимок ролей/прав (обновляется при изменении прав, чтобы не запрашивать их на каждый запрос)
  • Метки времени: created-at, last-seen-at, expires-at
  • CSRF-токен (если не используется исключительно SameSite=Strict)
  • Любое состояние сессии, нужное приложению (активный workspace, feature-флаги, флаг прохождения MFA)

Бэкенды для хранения вполне обычные: таблица в Postgres или MySQL, Redis для быстрой инвалидации по TTL, SQLite для небольших приложений. Большинство веб-фреймворков поставляются с middleware для сессий, которое всё это оборачивает. Для Express в gist рекомендуется связка express-session + connect-session-knex. Django, Rails, Laravel, ASP.NET и Phoenix поддерживают сессии из коробки.

Отзыв, ротация и принудительный выход

Всё это делается одним запросом. Чтобы выгнать пользователя, удалите строку его сессии. Чтобы принудительно разлогинить при смене пароля, удалите все строки его сессий. Чтобы выполнить ротацию идентификатора сессии при повышении привилегий, сгенерируйте новый ID, скопируйте строку и удалите старую. Ничего из этого не требует изменений в формате cookie или ключах подписи.

Именно это свойство авторы jwt-for-sessions постоянно пытаются воссоздать с помощью refresh-токенов, списков блокировок (denylists) и ротации ключей подписи - в результате заново изобретая сессии, только с лишними шагами.

Защита от CSRF

SameSite=Lax блокирует самые распространённые векторы CSRF, но не даёт полной защиты (особенно при GET-запросах верхнего уровня, меняющих состояние, которых в любом случае быть не должно). Традиционный паттерн - CSRF-токен сессии, который сервер вставляет в формы или отдаёт в ответе на первый GET-запрос, а клиент возвращает обратно при каждом запросе, изменяющем состояние. Фреймворки обычно настраивают это автоматически.

SPA и мобильные приложения

Сессии на cookie работают и для SPA. Браузер одинаково обрабатывает cookie как для fetchcredentials: 'include'), так и для обычных переходов по страницам. Конфигурация CORS должна разрешать передачу credentials при кросс-доменных вызовах, а SameSite нужно настроить соответствующим образом.

В нативных мобильных приложениях часто используют Bearer-токены - это как раз разумное место для короткоживущего подписанного токена (где paseto подошёл бы лучше, чем JWT) с обновлением через сервер авторизации. Аргументы в пользу сессий в браузере здесь применимы не в полной мере.

Связанные страницы

  • jwt-for-sessions - антипаттерн, альтернативой которому выступает эта концепция
  • paseto - более продуманная спецификация короткоживущих токенов для редких случаев, когда они действительно нужны
  • samsch-jwt-auth-gist - краткие аргументы в пользу выбора сессий вместо JWT