Где на клиенте следует хранить JWT-токен и какие у этого есть риски?

Ответ

JWT-токен хранится на стороне клиента. Выбор места хранения — это компромисс между удобством и безопасностью. Основные варианты и связанные с ними риски:

  1. localStorage / sessionStorage

    • Описание: Хранилище в браузере, доступное через JavaScript. sessionStorage очищается при закрытии вкладки.
    • Плюс: Простота реализации.
    • Минус: Уязвимость к XSS-атакам (Cross-Site Scripting). Если злоумышленник внедрит свой скрипт на страницу, он сможет прочитать и украсть токен.
      
      // Сохранение токена
      localStorage.setItem('jwt_token', 'your.jwt.token');

    // Получение токена для заголовка Authorization const token = localStorage.getItem('jwt_token');

  2. HttpOnly Cookie

    • Описание: Cookie, которые автоматически отправляются с каждым HTTP-запросом на тот же домен, но недоступны для чтения из JavaScript на клиенте.
    • Плюс: Встроенная защита от XSS-атак, так как скрипты не могут прочитать токен.
    • Минус: Уязвимость к CSRF-атакам (Cross-Site Request Forgery). Требует дополнительных мер защиты (атрибут SameSite=Strict или Lax, CSRF-токены).
      # Пример установки cookie в ответе (Flask)
      response.set_cookie(
      'access_token',
      'your.jwt.token',
      httponly=True,  # Запрещает доступ из JS
      secure=True,    # Отправка только по HTTPS
      samesite='Strict' # Защита от CSRF
      )

Рекомендуемый подход (Token-Based Authentication)

Наиболее безопасной считается комбинация из двух токенов:

  • Access Token (короткоживущий): Хранится в памяти приложения (например, в переменной JavaScript). Используется для авторизации запросов. Его короткий срок жизни (5-15 минут) минимизирует ущерб в случае кражи.
  • Refresh Token (долгоживущий): Хранится в HttpOnly cookie. Используется исключительно для получения нового access token, когда старый истекает.

Этот подход сочетает защиту от XSS (токен не в localStorage) и снижает риски CSRF (критичные операции требуют access token, который не отправляется автоматически как cookie).