Cookie и сессии

Материал из llmdocs — справочник разработчика
Cookie и сессии
ИзобретательЛу Монтулли (Netscape, 1994)
СтандартRFC 6265 (2011), готовится обновление RFC 6265bis
ЗаголовкиSet-Cookie (ответ), Cookie (запрос)
Ограничение размераоколо 4 КБ на cookie
Ключевые атрибутыSecure, HttpOnly, SameSite, Domain, Path, Max-Age
Хранение сессийна сервере (по идентификатору) или в самом токене (JWT)

Cookie (англ. «печенье»; по-русски часто «куки») — небольшой фрагмент данных, который сервер просит браузер сохранить и затем автоматически получает обратно с каждым запросом к тому же сайту.[1] Протокол HTTP не хранит состояние: каждый запрос независим, и сервер не знает, что два запроса пришли от одного человека. Cookie решают эту проблему и служат основой сессий — механизма, благодаря которому сайт помнит, что вы вошли в аккаунт, что лежит в корзине и какой язык вы выбрали.

История

Cookie придумал в 1994 году Лу Монтулли, инженер Netscape, — для корзины интернет-магазина. Механизм быстро стал общим для всех браузеров; современные правила закреплены в RFC 6265 (2011), а его обновление RFC 6265bis вносит в стандарт атрибут SameSite и префиксы имён.[1][2] С ростом рекламной слежки в 2010-х годах cookie оказались в центре регулирования: европейские GDPR и директива ePrivacy требуют согласия пользователя на необязательные cookie — отсюда баннеры на сайтах.

Как работает

Сервер устанавливает cookie заголовком ответа Set-Cookie, браузер возвращает его заголовком Cookie:

HTTP/1.1 200 OK
Set-Cookie: sid=8f3a2c9e41b7; Path=/; Secure; HttpOnly; SameSite=Lax; Max-Age=1209600

GET /account HTTP/1.1
Host: example.com
Cookie: sid=8f3a2c9e41b7; lang=ru

Атрибуты

Атрибут Значение
Expires / Max-Age срок жизни; без них cookie «сессионный» и удаляется при закрытии браузера
Domain для каких доменов отправлять; без него — только для точного хоста
Path для каких путей отправлять
Secure только по HTTPS (см. TLS)
HttpOnly недоступен JavaScript через document.cookie — защищает от кражи при XSS
SameSite отправлять ли при запросах с других сайтов: Strict, Lax, None

SameSite — главная защита от CSRF. При Strict cookie не уходит ни при каком переходе с другого сайта; Lax разрешает обычные переходы по ссылкам (GET), но не фоновые запросы и отправку форм POST; None (только вместе с Secure) — отправка всегда. С 2020 года Chrome, а затем и другие браузеры считают cookie без атрибута Lax по умолчанию.[5]

Префиксы имён усиливают защиту: cookie с именем __Host-sid браузер примет, только если у него есть Secure, Path=/ и нет Domain — его нельзя подменить с поддомена.

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

Сессии

Сессия — состояние пользователя на сервере между запросами. Два основных подхода:

Сессия на сервере. После входа сервер генерирует случайный идентификатор, сохраняет данные сессии в хранилище (Redis, база, память) и отдаёт идентификатор в cookie. При каждом запросе по нему находятся данные.

  • плюсы: сессию можно мгновенно отозвать (выход, блокировка, смена пароля), в браузере нет ничего, кроме случайной строки;
  • минусы: нужно общее хранилище для всех экземпляров приложения.

Токен с данными (JWT). Данные пользователя и срок действия подписываются сервером и целиком хранятся на клиенте; сервер лишь проверяет подпись.[6]

  • плюсы: не нужно хранилище, удобно для распределённых систем и межсервисных вызовов;
  • минусы: токен нельзя отозвать до истечения срока без дополнительного «чёрного списка», а он — снова хранилище. Поэтому делают короткоживущие токены доступа и долгоживущие токены обновления.

Для обычного веб-сайта надёжный выбор по умолчанию — серверная сессия в cookie с атрибутами Secure; HttpOnly; SameSite=Lax. Хранить токены в localStorage рискованно: их сможет прочитать любой внедрённый скрипт.

Безопасность сессий

Рекомендации OWASP:[4]

  • идентификатор — не менее 128 бит из криптографически стойкого генератора;
  • выдавать новый идентификатор после входа — иначе возможна фиксация сессии (злоумышленник заранее подсовывает жертве известный ему идентификатор);
  • ограничивать время жизни: абсолютное и по бездействию;
  • при выходе уничтожать сессию на сервере, а не только cookie в браузере;
  • повторно запрашивать пароль или второй фактор для критичных действий (см. Двухфакторная аутентификация).

Cookie, установленные не сайтом из адресной строки, а встроенным содержимым другого домена (рекламой, счётчиком), называют сторонними (third-party). Они позволяли следить за пользователем на разных сайтах. Safari и Firefox блокируют или изолируют их по умолчанию; Google несколько лет готовил их отключение в Chrome, но в итоге отказался от этого плана. Для встроенных сервисов, которым действительно нужно состояние, браузеры предлагают разделённые cookie (CHIPS, атрибут Partitioned) и Storage Access API.

См. также

Источники

  1. RFC 6265 — HTTP State Management Mechanism
  2. IETF draft — Cookies: HTTP State Management Mechanism (RFC 6265bis)
  3. MDN — Using HTTP cookies
  4. OWASP — Session Management Cheat Sheet
  5. web.dev — SameSite cookies explained
  6. RFC 7519 — JSON Web Token (JWT)