Каковы преимущества и недостатки хранения JWT в cookie по сравнению с Authorization header?

Ответ

Выбор между хранением JWT в cookie и передачей через заголовок Authorization — это компромисс между удобством и безопасностью, в частности, защитой от XSS и CSRF атак.

Хранение в cookie

Токен автоматически отправляется браузером с каждым запросом на тот же домен.

  • Плюсы:

    • Защита от XSS: Если установить флаг HttpOnly, токен становится недоступным для JavaScript на клиенте, что является основной защитой от кражи токена через XSS-уязвимости.
    • Простота: Не требует дополнительного кода на клиенте для прикрепления токена к запросам.
  • Минусы:

    • Уязвимость к CSRF (Cross-Site Request Forgery): Поскольку браузер отправляет cookie автоматически, злоумышленник может заставить пользователя выполнить нежелательное действие на вашем сайте со стороннего ресурса. Для защиты необходимо использовать SameSite атрибут (Strict или Lax) и/или CSRF-токены.
# Пример установки защищенного cookie в Flask
response.set_cookie(
    'access_token',
    value=jwt_token,
    httponly=True,  # Защита от XSS
    secure=True,    # Отправка только по HTTPS
    samesite='Lax'  # Защита от CSRF
)

Хранение в localStorage / sessionStorage и передача в Authorization header

Токен хранится в веб-хранилище браузера и вручную прикрепляется к каждому API-запросу.

  • Плюсы:

    • Защита от CSRF: Токен не отправляется автоматически, поэтому CSRF-атаки невозможны.
    • Гибкость: Легко работает с разными доменами и поддоменами. Является стандартом для API, используемых мобильными и нативными приложениями.
  • Минусы:

    • Уязвимость к XSS: Если на сайте есть XSS-уязвимость, злоумышленник может выполнить JS-код, который украдет токен из localStorage и отправит на свой сервер.
    • Требует реализации: Необходимо писать код на клиенте (например, interceptor в Axios) для добавления заголовка Authorization: Bearer <token> ко всем защищенным запросам.
// Пример отправки запроса с токеном из localStorage
const token = localStorage.getItem('jwt_token');

fetch('/api/data', {
  method: 'GET',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  }
});

Рекомендация:

  • Для традиционных веб-приложений (server-side rendering) предпочтительнее использовать cookie с флагами HttpOnly, Secure и SameSite=Strict.
  • Для Single Page Applications (SPA) и мобильных клиентов чаще используется Authorization header. Для повышения безопасности в SPA рекомендуется хранить токен в памяти приложения, а не в localStorage, чтобы минимизировать окно для XSS-атак.