Хранилища
Вопрос
Куда класть токен и чем cookie отличается от localStorage?
Короткий ответ
localStorage живёт, пока его не очистят, общий для вкладок одного источника, только строки, синхронное API, лимит порядка нескольких мегабайт. sessionStorage умирает вместе с вкладкой и между вкладками не шарится. Оба доступны любому скрипту страницы. Токен там читает XSS так же легко, как переменную.
Cookie уходит на сервер с запросами на этот хост, если не стоит фильтр. HttpOnly запрещает чтение из JS: скрипт украсть такую cookie не может. Secure шлёт только по HTTPS. SameSite ограничивает отправку с чужого сайта: Lax по умолчанию в современных браузерах режет большинство кросс-сайтовых запросов, None нужен явный Secure и как раз для кросс-сайтовой cookie.
IndexedDB — асинхронная база во вкладке для больших структур. Для пары настроек интерфейса она избыточна.
Разбор
Сессионная cookie без Max-Age и Expires живёт до закрытия браузера. Постоянная задаёт срок. Path и Domain сужают, куда её прикладывать. Широкий Domain на родительском хосте светит cookie поддоменам.
Память вкладки (переменная, Pinia) умирает при перезагрузке. Её не путают с sessionStorage: перезагрузка ту же вкладку хранилище сессии сохраняет, закрытие вкладки — нет.
Квота и режим инкогнито могут выкинуть запись. setItem бросает, если места нет. Секрет в localStorage переживёт XSS дольше, чем токен только в памяти: вредный скрипт прочитает его в любой момент после внедрения.
На что смотрят на senior
Доступ к API лучше держать в httpOnly-cookie сессии, чем в localStorage, если бэкенд это умеет. Тогда XSS не вычитывает токен одной строкой. CSRF при cookie всё ещё возможен: браузер сам приложит cookie. Его закрывают SameSite, проверкой origin и отдельным CSRF-токеном на небезопасных методах, если SameSite недостаточно.
localStorage синхронный и на большом значении блокирует главный поток. Туда не кладут кэш каталога на мегабайты. Для такого ближе IndexedDB или память с догрузкой по сети.
Типичные ошибки
- Хранить access token в
localStorageи считать это «безопасной сессией». - Ждать, что
sessionStorageодной вкладки виден в другой. - Путать
SameSiteи CORS. Одно про cookie, другое про чтение ответа скриптом. - Писать в хранилище объект без
JSON.stringifyи получать строку"[object Object]".
Задача
Токен лежит в localStorage. Вторая вкладка того же сайта его видит, вкладка после закрытия и нового открытия тоже. Что из этого сломается, если переложить токен в sessionStorage?
Показать ответ
Вторая вкладка его не увидит: у каждой вкладки свой sessionStorage.
Закрытие вкладки хранилище сессии уничтожает. Новая вкладка будет пустой. Перезагрузка той же вкладки значение сохраняет — это не то же самое, что закрыть её.
Оба хранилища читаются из JS. Перенос в sessionStorage не добавляет HttpOnly: от XSS это не защита. Такой флаг бывает у cookie, не у web storage.