Хранение токенов и их обновление
↑ 5.5 Аутентификация и доступ: Keycloak, SSO, ACL · ← Предыдущая · → Следующая
Зачем это на собесе
«Где хранить токен?» — вопрос с компромиссами XSS и CSRF.
Объяснение
| Место | XSS | CSRF | Переживает перезагрузку | Комментарий |
|---|---|---|---|---|
| Память (переменная/Pinia без persist) | сложнее украсть постоянно, но скрипт в странице всё равно может вызвать API | нет | нет | лучший вариант для access; восстановление через refresh cookie |
localStorage / sessionStorage | токен читаем любым скриптом | нет | да / вкладка | распространено, но рискованно при XSS |
HttpOnly cookie | не читается JS | уязвимость к CSRF — нужны SameSite, CSRF-токены | да | предпочтительно для refresh и сессий |
| BFF (сервер хранит токены) | токенов в браузере нет | защита CSRF | да (cookie сессии) | наиболее безопасная схема для SPA |
| IndexedDB, Service Worker | как localStorage | — | да | не лучше |
Рекомендуемая схема:
- Access token — в памяти.
- Refresh token —
HttpOnly; Secure; SameSitecookie (или полностью на BFF). - При загрузке страницы — silent refresh через cookie → access в память.
- Ротация refresh-токена, отзыв при выходе.
- Строгий CSP, экранирование, обновление зависимостей (снижают риск XSS).
Обновление в нескольких вкладках:
const lock = navigator.locks; // Web Locks: одна вкладка обновляет, остальные ждут
export async function refreshOnce() { return lock.request("refresh", async () => { if (tokenValid()) return; await doRefresh(); channel.postMessage("refreshed"); }); }Выход: очистка стора, кэша Vue Query, IndexedDB, отзыв токена, редирект на logout IdP; синхронизация выхода между вкладками (storage/BroadcastChannel).
Дополнительно: Content Security Policy, Subresource Integrity, Trusted Types, отсутствие токенов в URL/логах/аналитике.
Нюансы и подводные камни
- «Токен в
localStorage» удобен, но любая XSS-уязвимость = кража токена. HttpOnlycookie без CSRF-защиты открывает CSRF.- Долгоживущие access-токены увеличивают ущерб.
- Токены попадают в отчёты об ошибках и логи — фильтруйте (Sentry
beforeSend). - Логаут только на клиенте не отзывает токен на сервере.
Практика
- Реализуйте access в памяти + refresh в cookie с silent refresh.
- Добавьте синхронизацию выхода между вкладками.
- Настройте фильтрацию токенов в Sentry.
Вопросы с ответами
Где безопаснее хранить токен?
Access — в памяти, refresh — в
HttpOnlycookie или на сервере (BFF);localStorageуязвим при XSS.
Что делать при выходе?
Отозвать токены на сервере, очистить состояние и кэши, завершить SSO-сессию.