Пошук уроків, статей та іншого контенту
Три способи зберегти дані в браузері — і чому вибір неправильного може ненавмисно розлогінити користувача або передати зайві дані на сервер.
localStorage, sessionStorage і cookies можуть зберігати дані в браузері, але вони призначені для різних задач:
localStorage — довготривале сховище для даних конкретного сайту.
sessionStorage — тимчасове сховище на час роботи вкладки.
Cookies — невеликі значення, які браузер може автоматично надсилати на сервер разом із HTTP-запитами.
Найважливіше питання під час вибору:
Чи має це значення бути доступним JavaScript, чи його потрібно автоматично передавати серверу?
Якщо дані потрібні лише інтерфейсу, зазвичай підходить Web Storage (localStorage або sessionStorage). Якщо сервер має отримувати значення під час запитів, часто використовують cookies.
| Властивість | localStorage | sessionStorage | Cookies | |---|---|---|---| | Час життя | До явного видалення або очищення даних | До завершення сесії вкладки | Визначається атрибутами cookie | | Доступ із JavaScript | Так | Так | Так, якщо немає HttpOnly | | Автоматично надсилаються на сервер | Ні | Ні | Так, для відповідних запитів | | Область видимості | Origin | Origin і вкладка | Domain, path та інші атрибути | | Типовий обсяг | Значно більший за cookies, ліміт залежить від браузера | Значно більший за cookies, ліміт залежить від браузера | Невеликий, зазвичай близько 4 КБ на одну cookie | | Основне призначення | Налаштування, кеш, стан застосунку | Тимчасовий стан форми або вкладки | Сесія, авторизація, серверні параметри |
У таблиці наведено загальну картину. Реальні ліміти Web Storage залежать від браузера та умов зберігання.
localStoragelocalStorage зберігає рядки, пов’язані з конкретним origin — комбінацією протоколу, домену та порту.
Дані залишаються після:
перезавантаження сторінки;
закриття й повторного відкриття браузера;
переходу користувача на інші сторінки.
Вони зникнуть лише після явного видалення, очищення даних сайту або іншої дії браузера.
// Зберігаємо тему інтерфейсу
localStorage.setItem("theme", "dark");
// Читаємо значення
const theme = localStorage.getItem("theme");
if (theme === "dark") {
document.body.classList.add("dark-theme");
}
// Видаляємо конкретне значення
localStorage.removeItem("theme");
// Очищаємо все сховище поточного origin
localStorage.clear();localStorage зберігає лише рядки. Для масивів та об’єктів потрібно використовувати JSON:
const settings = {
language: "uk",
notifications: true
};
// Серіалізація об'єкта в рядок
localStorage.setItem("settings", JSON.stringify(settings));
// Читання та перетворення рядка назад в об'єкт
const savedSettings = localStorage.getItem("settings");
const parsedSettings = savedSettings
? JSON.parse(savedSettings)
: null;localStorageЦе хороший варіант для:
темної або світлої теми;
мови інтерфейсу;
локальних налаштувань;
стану фільтрів;
нескладного кешу даних;
чернетки, яку потрібно зберігати між відвідуваннями.
Наприклад, якщо користувач вибрав українську мову, немає потреби відправляти цю інформацію на сервер під час кожного запиту. Її можна залишити в localStorage.
localStoragelocalStorage не слід використовувати для:
паролів;
секретних ключів;
токенів із високими вимогами до безпеки;
великих файлів;
даних, які гарантовано мають зберігатися без втрат.
API синхронний: операції читання та запису блокують виконання JavaScript на короткий час. Для невеликих налаштувань це зазвичай непомітно, але великі обсяги даних можуть негативно вплинути на продуктивність.
sessionStoragesessionStorage має схожий API, але інший час життя. Дані належать конкретному origin і конкретному контексту вкладки.
Зазвичай вони зберігаються під час:
навігації між сторінками в межах вкладки;
перезавантаження сторінки;
переходу між маршрутами односторінкового застосунку.
Після закриття вкладки дані зазвичай видаляються. Відновлення сесії браузером може мати особливості, тому критично важливу інформацію не варто покладати лише на sessionStorage.
// Зберігаємо крок майстра у поточній вкладці
sessionStorage.setItem("checkoutStep", "2");
const step = sessionStorage.getItem("checkoutStep");
console.log(step); // "2"sessionStorageВін підходить для даних, які не потрібно переносити в нову вкладку:
поточний крок багатокрокової форми;
тимчасові фільтри;
стан відкритої сторінки;
дані, потрібні лише під час одного сценарію;
прапорець, що користувач уже побачив повідомлення в цій вкладці.
Наприклад, інтернет-магазин може зберігати в sessionStorage поточний крок оформлення замовлення. Якщо користувач оновить сторінку, він не втратить прогрес, але нова вкладка матиме окремий стан.
localStorageОсновна відмінність — час життя і область видимості:
localStorage спільний для вкладок цього origin і зберігається довго;
sessionStorage прив’язаний до конкретної вкладки та її сесії.
Обидва сховища доступні JavaScript, тому вони мають схожі ризики безпеки.
Cookie — це невеликий набір даних, який браузер зберігає для домену. На відміну від Web Storage, cookie може автоматично додаватися до HTTP-запитів:
Cookie: session_id=abc123Це робить cookies зручними для даних, які повинен отримувати сервер:
ідентифікатора сесії;
ознак авторизації;
налаштувань, які сервер читає до виконання JavaScript;
параметрів маршрутизації або локалі, якщо це потрібно серверній частині.
Cookie можна встановити JavaScript:
// Встановлюємо cookie до завершення поточної сесії браузера
document.cookie = "language=uk; Path=/";
// Читаємо всі доступні для JavaScript cookies
console.log(document.cookie);Однак document.cookie має незручний формат: воно повертає всі доступні cookies одним рядком. Для складнішої роботи потрібен власний парсер або серверний код.
Expires і Max-AgeБез атрибутів довготривалого терміну cookie часто називають сесійною: браузер зберігає її до завершення сесії.
Max-Age задає час життя в секундах:
document.cookie =
"language=uk; Max-Age=2592000; Path=/";У цьому прикладі cookie має жити приблизно 30 днів.
PathPath обмежує URL-шляхи, для яких cookie надсилатиметься:
document.cookie =
"checkout_mode=express; Path=/checkout";Така cookie призначена для запитів у межах /checkout.
DomainDomain визначає домен, для якого cookie доступна. Надто широке значення може зробити cookie доступною більшій кількості піддоменів, ніж потрібно.
Якщо Domain не вказати, cookie зазвичай буде прив’язана до поточного хоста. Це часто безпечніший і простіший варіант.
SecureSecure дозволяє надсилати cookie лише через HTTPS:
document.cookie =
"session_id=abc123; Secure; Path=/";Для production-застосунків cookies із чутливими даними мають використовувати HTTPS.
HttpOnlyHttpOnly забороняє читати cookie через JavaScript. Вона все одно надсилається браузером на сервер, але document.cookie її не покаже.
Важливо: встановити HttpOnly через JavaScript неможливо. Цей атрибут має додавати сервер у заголовку Set-Cookie.
Приклад серверної відповіді:
Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Lax; Path=/HttpOnly зменшує ризик викрадення cookie через шкідливий JavaScript, але не усуває саму вразливість XSS. Якщо зловмисний код виконується на сторінці, він все ще може виконувати дії від імені користувача.
SameSiteSameSite визначає, як cookie поводиться під час міжсайтових запитів:
Strict — найсуворіший режим;
Lax — поширений компроміс для сесійних cookies;
None — дозволяє міжсайтове використання, але потребує Secure.
Наприклад:
Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Lax; Path=/SameSite допомагає зменшити ризик CSRF, але конкретний режим потрібно узгоджувати з архітектурою застосунку. Якщо застосунок справді має працювати між різними сайтами, суворі налаштування можуть завадити легітимним запитам.
Для авторизації немає універсального правила, яке підходить кожному проєкту. Але є важлива практична відмінність.
localStorageПереваги:
легко читати з JavaScript;
зручно додавати до заголовка Authorization;
токен не надсилається на кожен запит автоматично.
Недолік:
будь-який JavaScript, що виконується в контексті сторінки, потенційно може прочитати токен;
XSS-вразливість може призвести до викрадення токена.
HttpOnlyПереваги:
JavaScript не може прочитати cookie;
браузер автоматично додає її до відповідних запитів;
серверу зручно працювати із традиційною сесією.
Недоліки:
потрібно правильно налаштувати SameSite, CSRF-захист та HTTPS;
cookie надсилається автоматично, тому сервер має уважно перевіряти походження запитів;
cookie додається до запитів, якщо її область дії налаштована надто широко.
Поширена схема для вебзастосунку:
Сервер створює сесію.
Сервер надсилає ідентифікатор сесії в cookie з HttpOnly, Secure і відповідним SameSite.
Браузер автоматично надсилає cookie на сервер.
Сервер перевіряє сесію під час кожного захищеного запиту.
Не варто зберігати пароль користувача ні в localStorage, ні в sessionStorage, ні в cookie.
fetchДля same-origin-запитів cookies зазвичай передаються браузером автоматично. Для запитів між різними origin потрібно явно налаштувати credentials:
const response = await fetch("https://api.example.com/profile", {
// Дозволяємо передавати cookies у міжorigin-запиті
credentials: "include"
});
const profile = await response.json();Сервер при цьому також має дозволити credentials у CORS-відповіді. Недостатньо змінити лише код клієнта.
Також важливо розрізняти:
cross-origin — інший протокол, домен або порт;
cross-site — інший сайт у сенсі політик cookies та SameSite.
Ці поняття пов’язані, але не є повністю однаковими.
Перед вибором поставте кілька запитань.
Так — розгляньте cookie.
Ні — Web Storage може бути простішим варіантом.
Так — localStorage або довготривала cookie.
Ні, лише в межах вкладки — sessionStorage або сесійна cookie.
Не зберігайте їх у Web Storage без чіткої причини.
Для сесійних ідентифікаторів розгляньте cookie з HttpOnly, Secure і правильною політикою SameSite.
Мінімізуйте термін життя та область дії даних.
Cookies для цього не підходять.
Web Storage має більші, але все одно обмежені квоти.
Для великих локальних даних варто розглянути IndexedDB.
Пароль не потрібно зберігати після входу. Сервер має перевірити пароль і створити сесію або видати відповідний токен.
localStorage без оцінки ризиківЦе поширений підхід, але XSS може відкрити доступ до такого токена. Потрібно захищати застосунок від XSS, мінімізувати строк життя токена та оцінити, чи не підходить безпечніша cookie-сесія.
HttpOnly повним захистом від XSSHttpOnly не дає прочитати cookie, але шкідливий скрипт усе ще може надсилати запити з браузера користувача. Це не замінює екранування даних, Content Security Policy та інші засоби захисту.
Cookies надсилаються разом із запитами, тому великий обсяг збільшує мережевий трафік і може спричинити перевищення обмежень. У cookie краще зберігати короткий ідентифікатор, а не весь стан користувача.
JSON.parseЗначення з Web Storage — це рядки. Якщо очікується JSON, потрібно враховувати пошкоджені або відсутні дані:
function readSettings() {
const rawValue = localStorage.getItem("settings");
if (!rawValue) {
return null;
}
try {
return JSON.parse(rawValue);
} catch {
// Видаляємо некоректні дані та повертаємо безпечне значення
localStorage.removeItem("settings");
return null;
}
}localStorageКористувач може очистити дані сайту, браузер може працювати в приватному режимі, а політики зберігання можуть змінюватися. Критичні дані потрібно зберігати на сервері або передбачати коректне відновлення.
Якщо браузер автоматично надсилає cookie, сервер має перевіряти, чи справді запит походить із дозволеного контексту. Для цього використовують SameSite, CSRF-токени, перевірку Origin або інші відповідні механізми.
SecureСесійні cookies мають передаватися лише через HTTPS. Інакше їх можна перехопити під час незахищеного з’єднання.
Для типового frontend-застосунку можна використовувати таку схему:
тема, мова та прості налаштування — localStorage;
тимчасовий стан форми в межах вкладки — sessionStorage;
серверна сесія — cookie з HttpOnly, Secure і продуманим SameSite;
великі локальні набори даних — IndexedDB;
паролі та інші секрети — не зберігати в браузері без необхідності.
Також корисно зберігати у Web Storage лише мінімальні дані. Наприклад, замість повного профілю користувача можна залишити локальний прапорець налаштування, а актуальний профіль отримувати із сервера.
localStorage підходить для довготривалих несекретних налаштувань.
sessionStorage підходить для тимчасового стану конкретної вкладки.
Cookies потрібні тоді, коли дані має автоматично отримувати сервер.
localStorage і sessionStorage доступні JavaScript, тому не є хорошим місцем для чутливих секретів.
Для сесійних cookies варто використовувати HttpOnly, Secure, SameSite і обмежений Path.
Cookies мають невеликий розмір і додаються до HTTP-запитів, тому їх не можна перетворювати на сховище всього стану застосунку.
Неправильний вибір може призвести не лише до зайвого трафіку, а й до викрадення токена, CSRF-проблем або втрати стану після закриття вкладки.