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