Cookies, localStorage или sessionStorage: где хранить данные
Практика3 минРедакция Innovialabs
Коротко
Cookies уходят на сервер с каждым запросом и подходят для сессий с флагами HttpOnly и Secure; localStorage хранит несекретные настройки долго, sessionStorage — до закрытия вкладки.
Короткий ответ
- Cookies — для данных, которые нужны серверу: прежде всего идентификатор сессии. Защищаются флагами
HttpOnly,Secure,SameSite. - localStorage — для несекретных данных, которые должны пережить закрытие браузера: тема, язык, черновик формы.
- sessionStorage — для временного состояния одной вкладки: шаг мастера, фильтры на время сессии.
Секреты — пароли, платёжные данные, долгоживущие токены — в localStorage и sessionStorage не хранятся вообще.
Сравнение
| Cookies | localStorage | sessionStorage | |
|---|---|---|---|
| Срок жизни | до Expires/Max-Age или до конца сессии браузера | пока не удалят | пока открыта вкладка |
| Размер | около 4 КБ на одну cookie | обычно несколько МБ на origin | обычно несколько МБ на origin |
| Отправка на сервер | автоматически с каждым запросом | нет | нет |
| Доступ из JS | да, если нет HttpOnly | да | да |
| Область видимости | домен и путь | origin | origin + конкретная вкладка |
| API | document.cookie, заголовок Set-Cookie | синхронный getItem/setItem | синхронный getItem/setItem |
Точные лимиты Web Storage зависят от браузера, поэтому не стоит рассчитывать на них впритык.
Cookies: когда данные нужны серверу
Cookie устанавливает сервер через заголовок или скрипт через document.cookie. Браузер сам прикрепляет её к запросам на подходящий домен.
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=86400
Что значат флаги:
- HttpOnly — cookie недоступна из JavaScript. Если на сайт внедрят вредоносный скрипт (XSS), он не сможет её прочитать.
- Secure — отправляется только по HTTPS.
- SameSite — ограничивает отправку при запросах с других сайтов и снижает риск CSRF.
Lax— разумное значение по умолчанию,Strict— строже,NoneтребуетSecureи нужен для сторонних сценариев. - Max-Age / Expires — срок жизни. Без них cookie живёт до закрытия браузера.
Минус cookies — они увеличивают каждый запрос. Не храните в них крупные данные.
localStorage: долгие несекретные данные
localStorage.setItem("theme", "dark");
const theme = localStorage.getItem("theme"); // "dark"
Хранит только строки, поэтому объекты сериализуют через JSON.stringify и разбирают через JSON.parse. Данные общие для всех вкладок одного origin, а событие storage позволяет синхронизировать вкладки.
Учтите:
- API синхронный — большие записи могут подтормаживать интерфейс.
- В приватном режиме и при запрете хранения доступ может выбросить исключение, поэтому оборачивайте вызовы в
try/catch. - Любой скрипт на странице, включая сторонний, может прочитать localStorage.
sessionStorage: состояние одной вкладки
Тот же API, но данные живут только в текущей вкладке. Перезагрузка их не стирает, закрытие вкладки — стирает. Две вкладки одного сайта не видят sessionStorage друг друга.
Подходит для многошаговых форм, временных фильтров, позиции в списке.
Что нельзя хранить на клиенте
- Пароли — ни в каком виде.
- Данные банковских карт и другие платёжные реквизиты.
- Долгоживущие токены доступа и refresh-токены в localStorage/sessionStorage: при XSS их украдут. Для сессий надёжнее cookie с
HttpOnly. - API-ключи с серверными правами — всё, что попало в браузер, пользователь может увидеть.
- Персональные данные, без которых интерфейс может обойтись.
- Права и роли как источник истины. Клиент может их подменить, проверка всегда на сервере.
Как выбрать
- Нужно серверу при каждом запросе? — cookie.
- Секретно? — только HttpOnly-cookie или вообще только сервер.
- Должно пережить закрытие браузера? — localStorage.
- Нужно только в этой вкладке? — sessionStorage.
- Много структурированных данных или файлов? — IndexedDB.
Частые ошибки
- JWT в localStorage «потому что так в туториале».
- Cookie без
SecureиSameSiteна продакшене. - Чтение localStorage без
try/catchи без значения по умолчанию. - Хранение больших объектов в cookies, которые утяжеляют каждый запрос.
Подробности о флагах — в документации MDN.