Что такое cookie в вебе: теория, атрибуты и безопасность
Что такое cookie?
Что такое cookie
Cookie — это небольшой фрагмент данных (пара «имя=значение» с метаданными), который сервер просит браузер сохранить, а браузер затем автоматически отправляет обратно на сервер при последующих запросах в рамках заданной области видимости (домен, путь, контекст).
Ключевая идея cookie — привязать несколько независимых HTTP-запросов к единому контексту, например к авторизованной сессии, предпочтениям интерфейса или состоянию корзины, если оно хранится на стороне сервера.
Как cookie передаётся по HTTP
Cookie устанавливается сервером через заголовок Set-Cookie в HTTP-ответе, а затем возвращается браузером через заголовок Cookie в HTTP-запросе.
Пример ответа сервера с установкой cookie:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Set-Cookie: session_id=abc123; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=3600
<html>...</html>
Пример последующего запроса браузера к тому же сайту:
GET /profile HTTP/1.1
Host: example.com
Cookie: session_id=abc123
Схема обмена:
┌──────────┐ ┌────────────┐
│ Браузер │ 1) Запрос │ Сервер │
│ ├────────────────▶│ │
│ │ │ 2) Ответ │
│ │ Set-Cookie │ │
│ │◀────────────────┤ │
│ │ 3) След. запрос │ │
│ │ Cookie: ... │ │
└──────────┘ └────────────┘
Основные свойства и ограничения
Cookie имеет ограниченный размер (типично около (4096) байт на одну cookie) и ограничения по количеству на домен (зависит от браузера и политики, часто десятки/сотни).
Cookie отправляется в каждом подходящем HTTP-запросе автоматически, поэтому увеличение размера и количества cookie повышает сетевые накладные расходы и может замедлять загрузку страниц.
Область видимости: Domain, Path, срок жизни
Область видимости определяет, когда браузер будет прикреплять cookie к запросу.
Domainзадаёт, каким доменам доступна cookie, напримерDomain=example.comобычно охватывает поддомены (в рамках правил браузера)Pathограничивает URL-пути, напримерPath=/appозначает отправку на/app/*Expiresзадаёт момент истечения (дата/время)Max-Ageзадаёт время жизни в секундах, например (3600)- При отсутствии
Expires/Max-Agecookie обычно считается «сессионной» и удаляется при завершении сессии браузера (точное поведение зависит от настроек и режима восстановления сессии)
Пример удаления cookie (типовой подход — истечь «в прошлом»):
Set-Cookie: session_id=; Path=/; Max-Age=0
Атрибуты безопасности: Secure, HttpOnly, SameSite
Атрибуты безопасности уменьшают риск утечек и атак, но не делают хранение данных в cookie «абсолютно безопасным».
Таблица атрибутов:
| Атрибут | Что делает | Когда применять | Типичная ошибка |
|---|---|---|---|
Secure | Отправка только по HTTPS | Всегда для чувствительных cookie | Оставлять без Secure на HTTPS-сайте |
HttpOnly | Запрет доступа из JavaScript (document.cookie) | Для сессионных идентификаторов | Пытаться читать такую cookie на клиенте |
SameSite=Lax/Strict/None | Ограничение отправки в кросс-сайт контекстах | Защита от CSRF и трекинга | Ставить SameSite=None без Secure (обычно блокируется) |
Пояснение по SameSite:
Laxчасто является разумным значением по умолчанию: cookie обычно отправляется при «безопасной» навигации верхнего уровня на сайт, но ограничивается в большинстве фоновых кросс-сайт запросовStrictжёстче: cookie почти не отправляется при переходах с других сайтовNoneразрешает кросс-сайт отправку, но в современных браузерах обычно требуетSecure
SameSite трактуется как Lax (поведение зависит от браузера и версии).Современные дополнения: Partitioned (CHIPS), префиксы, Priority
В условиях ужесточения приватности появились механизмы, ограничивающие «третьесторонние» cookie и трекинг, а также добавляющие более точные правила хранения.
Partitioned(CHIPS) позволяет хранить cookie в «разделённом» виде по верхнему сайту (top-level site), что полезно для встраиваемых виджетов и авторизации в iframe при минимизации трекинга- Префикс
__Secure-требует наличияSecureи установки по HTTPS - Префикс
__Host-обычно требуетSecure, установки по HTTPS, отсутствияDomainиPath=/, что уменьшает риск подмены области видимости Priority(напримерPriority=High) может влиять на то, какие cookie будут удержаны при переполнении лимитов
Пример с префиксом __Host-:
Set-Cookie: __Host-session=abc123; Path=/; Secure; HttpOnly; SameSite=Lax
Partitioned и политики вокруг третьесторонних cookie зависят от браузера; архитектуру аутентификации для встроенных контекстов следует проектировать с учётом этих различий.Cookie и клиентские хранилища: что выбирать
Cookie — не единственный способ хранить состояние, и часто не самый удобный для данных, которые нужны именно JavaScript-коду.
Сравнение:
| Механизм | Авто-отправка на сервер | Доступ из JS | Типичный объём | Основные кейсы |
|---|---|---|---|---|
| Cookie | Да | Да, кроме HttpOnly | Небольшой | Сессии, флаги, совместимость с HTTP |
localStorage | Нет | Да | Больше, чем cookie | Настройки UI, кэш состояния |
sessionStorage | Нет | Да | Больше, чем cookie | Данные в рамках вкладки |
| IndexedDB | Нет | Да | Значительно больше | Офлайн-данные, сложные структуры |
Обычно идентификатор сессии хранится в cookie (часто HttpOnly), а сами пользовательские данные и состояние — на сервере или в других хранилищах, чтобы не увеличивать трафик и не повышать риск утечек.
Типовые сценарии использования
- Сессии: cookie хранит идентификатор
session_id, сервер хранит состояние сессии и связывает его с пользователем - Персонализация: язык, тема, экспериментальные флаги, если нет чувствительных данных и размер мал
- Безопасность: CSRF-токены иногда хранятся в cookie (в зависимости от паттерна), но важно понимать модель угроз и наличие XSS-защиты
- Аналитика: исторически широко применялись третьесторонние cookie, но эта область активно ограничивается политиками приватности браузеров
Риски: XSS, CSRF, фиксация сессии
Основные угрозы и меры:
- XSS: при успешной инъекции скрипта злоумышленник может прочитать не-
HttpOnlycookie черезdocument.cookie; снижение риска достигаетсяHttpOnlyдля сессионных cookie, строгим CSP, экранированием/валидацией ввода, безопасной генерацией HTML - CSRF: браузер может автоматически отправить cookie на целевой сайт при кросс-сайт запросе; снижение риска достигается
SameSite=Lax/Strict, проверкой CSRF-токенов, проверкойOrigin/Refererтам, где уместно - Фиксация сессии: навязывание жертве известного
session_id; снижение риска достигается регенерацией идентификатора после логина и привязкой к контексту
Практика: чтение и установка на клиенте
Установка cookie из JavaScript возможна, но без доступа к флагу HttpOnly и с ограничениями на некоторые атрибуты.
Пример чтения и записи:
// Запись (часть атрибутов задаётся строкой)
document.cookie = `theme=dark; Path=/; Max-Age=2592000; SameSite=Lax; Secure`;
// Чтение всех доступных cookie (HttpOnly сюда не попадёт)
const all = document.cookie; // строка вида "a=1; b=2"
const theme = all
.split('; ')
.find(part => part.startsWith('theme='))
?.split('=')[1];
Важно учитывать, что document.cookie работает со строками и требует аккуратного парсинга и кодирования значений, например через encodeURIComponent(...) при записи и decodeURIComponent(...) при чтении.
Практика: установка на сервере
На сервере cookie обычно устанавливается вместе с логикой сессий.
Пример на Node.js (HTTP):
import http from 'node:http';
const server = http.createServer((req, res) => {
if (req.url === '/login') {
// Обычно тут создаётся сессия на сервере и генерируется идентификатор
const sid = 'abc123';
res.setHeader('Set-Cookie', [
`session_id=${sid}; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=3600`,
]);
res.statusCode = 200;
res.end('ok');
return;
}
const cookieHeader = req.headers.cookie ?? '';
res.statusCode = 200;
res.end(`cookies: ${cookieHeader}`);
});
server.listen(3000);
На практике идентификатор сессии должен быть непредсказуемым (криптографически стойким), а сервер должен проверять срок жизни, привязки и права доступа.
Итого: cookie — это маленький фрагмент данных, устанавливаемый сервером и автоматически отправляемый браузером в HTTP-запросах по правилам области видимости и атрибутам безопасности; основное применение — сессии и небольшие настройки, а ключевые риски связаны с XSS/CSRF и неправильными атрибутами.