Куки обзор #
Cookie (куки) — небольшие пары «имя=значение», которые браузер прикрепляет к запросам на тот же сайт. Сервер выставляет их заголовком Set-Cookie; JavaScript может читать и записывать часть кук через document.cookie, но с важными ограничениями.
Как выглядит cookie #
Сервер отвечает, например:
Set-Cookie: sessionId=abc123; Path=/; HttpOnly; Secure; SameSite=Lax
Браузер сохраняет cookie и отправляет её обратно:
Cookie: sessionId=abc123
Так поддерживают сессии входа, корзины на сервере, A/B-тесты и аналитику — в зависимости от настроек.
document.cookie #
В JS куки доступны одной строкой, не как удобный Map:
document.cookie = 'ui_lang=ru; path=/; max-age=31536000'
console.log(document.cookie) // "ui_lang=ru; other=..." — все видимые куки origin
Чтобы прочитать одну куку, строку нужно разобрать:
function readCookie(name) {
const prefix = `${name}=`
const pair = document.cookie.split('; ').find((row) => row.startsWith(prefix))
return pair ? decodeURIComponent(pair.slice(prefix.length)) : null
}
readCookie('ui_lang') // "ru" или null
Запись перезаписывает куку с тем же именем и path; удаление — установка max-age=0 или прошедшей даты expires.
document.cookie = 'ui_lang=; path=/; max-age=0'
Ограничения document.cookie #
| Ограничение | Следствие |
|---|---|
| Только строка | Нет getItem/setItem как у localStorage |
| Нет списка метаданных из JS | Из скрипта не видно HttpOnly, Secure, SameSite |
| Размер ~4 КБ на cookie | Не кладите большие JSON |
| Отправка с каждым запросом | Лишний трафик, если cookie раздута |
// все куки origin в одной строке — неудобно для сложной логики
document.cookie.split('; ').forEach((row) => console.log(row))
Для клиентских настроек (тема, язык) чаще берут localStorage; куки оставляют там, где сервер должен видеть значение в HTTP-заголовке.
HttpOnly — идея безопасности #
Флаг HttpOnly запрещает доступ к cookie из JavaScript. Такую куку браузер отправит на сервер, но document.cookie её не покажет и скрипт не сможет перезаписать.
// sessionId с HttpOnly — в консоли document.cookie её нет
// XSS-скрипт не украдёт токен через document.cookie
Это основной способ хранить идентификатор сессии: даже при внедрении чужого скрипта на страницу HttpOnly-cookie остаётся недоступной для чтения из JS.
Выставить HttpOnly из браузерного скрипта нельзя — только сервер в Set-Cookie.
Secure, SameSite, Domain #
Кратко о сопутствующих флагах (полностью задаются сервером):
- Secure — cookie уходит только по HTTPS.
- SameSite (
Strict,Lax,None) — когда cookie прикрепляется к кросс-сайтовым запросам; важно для CSRF и iframe. - Domain и Path — на каких URL cookie действует.
Фронтенд должен знать, что сессионная cookie, скорее всего, HttpOnly, и не пытаться дублировать её в localStorage.
Cookies vs Web Storage #
| Cookies | localStorage | |
|---|---|---|
| Отправка на сервер | Автоматически | Нет |
| Лимит | ~4 КБ на cookie | ~5 МБ на origin |
| API в JS | document.cookie (строка) | getItem / setItem |
| HttpOnly | Да (без доступа из JS) | Нет такого флага |
// клиентская настройка — storage
localStorage.setItem('sidebar-open', '1')
// серверная сессия — Set-Cookie: sid=...; HttpOnly; Secure
// JS проверяет авторизацию через fetch('/api/me'), а не через чтение sid
Итог #
- Куки связывают браузер и сервер через заголовки
Set-CookieиCookie. document.cookie— строковый API: неудобен, но достаточен для простых клиентских флагов.- HttpOnly скрывает cookie от JavaScript — стандарт для session id.
- Для UI-настроек удобнее Web Storage; для сессии и CSRF-политики — куки с флагами на бэкенде.