Что такое 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 повышает сетевые накладные расходы и может замедлять загрузку страниц.

Хранение больших данных в cookie считается плохой практикой из‑за лимитов и того, что cookie «ездит» в каждом запросе.

Область видимости: Domain, Path, срок жизни

Область видимости определяет, когда браузер будет прикреплять cookie к запросу.

  • Domain задаёт, каким доменам доступна cookie, например Domain=example.com обычно охватывает поддомены (в рамках правил браузера)
  • Path ограничивает URL-пути, например Path=/app означает отправку на /app/*
  • Expires задаёт момент истечения (дата/время)
  • Max-Age задаёт время жизни в секундах, например (3600)
  • При отсутствии Expires/Max-Age cookie обычно считается «сессионной» и удаляется при завершении сессии браузера (точное поведение зависит от настроек и режима восстановления сессии)

Пример удаления 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
В современных браузерах распространена политика, при которой cookie без явного 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: при успешной инъекции скрипта злоумышленник может прочитать не-HttpOnly cookie через document.cookie; снижение риска достигается HttpOnly для сессионных cookie, строгим CSP, экранированием/валидацией ввода, безопасной генерацией HTML
  • CSRF: браузер может автоматически отправить cookie на целевой сайт при кросс-сайт запросе; снижение риска достигается SameSite=Lax/Strict, проверкой CSRF-токенов, проверкой Origin/Referer там, где уместно
  • Фиксация сессии: навязывание жертве известного session_id; снижение риска достигается регенерацией идентификатора после логина и привязкой к контексту
Хранение в cookie персональных данных (например, email, роли, права) без криптографической защиты считается опасным, так как cookie может быть украдена, подменена или утечь через логи/расширения.

Практика: чтение и установка на клиенте

Установка 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 и неправильными атрибутами.