Безопасное хранение токенов

↑ 7.3 Безопасность фронтенда · ← Предыдущая · → Следующая

Желательно~3 мин чтенияУровень: senior

Зачем это на собесе

Один из самых обсуждаемых вопросов: «где хранить JWT». Нужно взвесить компромиссы.

Варианты

МестоПлюсыМинусы
localStorageпростодоступен любому скрипту → украдут через XSS
sessionStorageживёт до закрытия вкладкита же XSS-уязвимость
Память (переменная)недоступна после XSS-сессии в другой вкладкетеряется при перезагрузке
Cookie HttpOnly; Secure; SameSiteJS токен не прочитаетнужна CSRF-защита

Рекомендуемая схема

  • access-токен — короткоживущий (5–15 минут), держим в памяти;
  • refresh-токен — в HttpOnly; Secure; SameSite=Strict/Lax cookie, путь /auth/refresh;
  • при перезагрузке страницы запрашиваем новый access по refresh;
  • rotation refresh-токенов и детект повторного использования на сервере;
  • выход: сервер отзывает refresh, cookie удаляется.
let accessToken: string | null = null
 
export async function refresh() {
  const r = await fetch('/auth/refresh', { method: 'POST', credentials: 'include' })
  accessToken = (await r.json()).accessToken
}

OIDC и SPA

Для SPA: Authorization Code Flow с PKCE, без implicit flow. Библиотеки: oidc-client-ts, keycloak-js. Либо паттерн BFF (Backend for Frontend): токены живут на сервере, браузер получает только сессионную cookie.

Что ещё

  • не класть чувствительные данные в JWT (он читаем, не шифруется);
  • не логировать токены, скрывать из URL и Referer;
  • короткий TTL и проверка aud, iss, exp на бэкенде.

Вопросы с ответами