JWT проти сесій: який механізм автентифікації обрати?

Автентифікувати користувача означає при кожному запиті знати, хто він. Стикаються дві великі родини: серверні сесії, де сервер відстежує авторизованого користувача, і JSON Web Tokens (JWT), де ідентичність подорожує у підписаному токені, який несе клієнт. Вибір впливає на безпеку, здатність масштабуватися та легкість виходу користувача. Ось як визначитися залежно від вашого контексту.

Серверні сесії (stateful)

За сесії сервер створює ідентифікатор сесії під час входу, зберігає пов'язані дані (ідентичність, ролі, кошик) на стороні сервера (пам'ять, Redis, база даних) і повертає браузеру cookie, що містить лише цей ідентифікатор. При кожному запиті сервер читає cookie, знаходить сесію і знає, хто говорить.

  • Стан на стороні сервера: джерело правди залишається на сервері, клієнт несе лише непрозоре посилання.
  • Негайне відкликання: видалення сесії на стороні сервера миттєво відключає користувача.
  • Cookie: передається браузером автоматично, в ідеалі з атрибутами HttpOnly, Secure та SameSite.

JSON Web Tokens (stateless)

JWT - це самодостатній токен, що складається з трьох частин, закодованих у base64url і розділених крапками: header, payload (claims, наприклад ідентифікатор користувача та термін дії) та підпис. Сервер підписує токен під час входу; далі йому достатньо перевірити підпис, щоб довіряти вмісту, нічого не зберігаючи.

  • Без стану: уся потрібна інформація є в токені, серверу не потрібна спільна пам'ять.
  • Перевіряється всюди: будь-який сервіс, що знає ключ, може підтвердити токен, що зручно для розподілених архітектур і SSO.
  • Інструменти: ви можете оглянути токен нашим декодером JWT, перевірити його підпис верифікатором JWT або створити його генератором JWT.

Порівняльна таблиця

Критерій Серверна сесія JWT
СтанStateful (зберігається на сервері)Stateless (несе клієнт)
Сховище на серверіПотрібне (Redis, база)Жодного
ВідкликанняНегайнеСкладне до завершення терміну
Горизонтальна масштабованістьПотрібне спільне сховищеПриродна
Розмір передачіМалий (один ідентифікатор)Більший (підписані claims)
Між доменами / SSOОбмежуєПідходить
Поверхня XSSНизька, якщо cookie HttpOnlyВисока, якщо зберігається в localStorage

Безпека: XSS, CSRF та відкликання

Обидва підходи безпечні, якщо правильно реалізовані, але їхні ризики відрізняються.

  • XSS: cookie сесії HttpOnly недоступний для JavaScript, тому захищений від крадіжки через ін'єкцію. JWT, збережений у localStorage, навпаки, читається будь-яким скриптом, що робить його ласою ціллю. Зберігання JWT у cookie HttpOnly скасовує цю перевагу JWT, але повертає ризик CSRF.
  • CSRF: cookies надсилаються автоматично, тому без захисту вразливі до CSRF (атрибут SameSite, анти-CSRF токен). JWT, надісланий вручну в заголовку Authorization, цього не стосується.
  • Відкликання: це слабке місце JWT. Оскільки він самодостатній, його не можна скасувати до завершення терміну дії, не повернувши серверний стан (список відкликань, чорний список). Сесія видаляється миттєво.

Масштабованість та архітектура

На одному сервері сесії тривіальні. Щойно ви розподіляєте навантаження на кілька екземплярів, кожен екземпляр має мати доступ до сесій: потрібне спільне сховище (Redis) або sticky sessions. JWT тут сяє, бо будь-який екземпляр підтверджує токен без мережевого виклику чи спільного сховища.

  • Мікросервіси: JWT поширює ідентичність від одного сервісу до іншого без центральної бази.
  • Публічні та мобільні API: JWT уникає управління cookies на стороні нативного клієнта.
  • Класичний моноліт: сесія залишається простішою та безпечнішою за замовчуванням.

Коли обирати одне чи інше

Оберіть сесії, коли

  • Ви розробляєте класичний вебзастосунок із рендерингом на сервері
  • Негайне відкликання є критичним (банк, охорона здоров'я, бекофіс)
  • Ви хочете найбезпечніше рішення за замовчуванням, з найменшою кількістю пасток
  • Ваша інфраструктура без проблем витримує спільне сховище сесій

Оберіть JWT, коли

  • Ви надаєте API, яке споживають SPA, мобільні застосунки чи треті сторони
  • У вас архітектура мікросервісів або SSO між доменами
  • Вам потрібно масштабуватися горизонтально без спільного сховища
  • Ви приймаєте управління коротким терміном дії та оновленням токенів

Рекомендація

Для більшості вебзастосунків серверні сесії залишаються найбезпечнішим і найпростішим вибором: негайне відкликання, cookie HttpOnly та жодного управління токенами на стороні клієнта. Залиште JWT для випадків, де його відсутність стану дає справжню цінність: stateless API, мобільні застосунки, мікросервіси, SSO.

Якщо ви обираєте JWT, тримайте короткий термін дії (кілька хвилин) у поєднанні з refresh-токеном, збереженим у cookie HttpOnly, і передбачте список відкликань для чутливих випадків. Так ви поєднуєте найкраще з обох світів.

Поширені запитання

Чи зашифрований JWT?

Ні, за замовчуванням JWT лише підписаний, а не зашифрований. Його payload закодований у base64url і читається будь-ким, хто його перехопить. Ніколи не розміщуйте чутливі дані у відкритому вигляді в JWT. Щоб зашифрувати вміст, треба вдатися до JWE (JSON Web Encryption).

Де зберігати JWT на стороні клієнта?

Найбезпечніше - це cookie HttpOnly, Secure та SameSite, що захищає від крадіжки через XSS. localStorage простіший, але відкриває токен будь-якому шкідливому скрипту. Уникайте його для токенів із високими привілеями.

Як вийти з облікового запису користувача з JWT?

Оскільки токен самодостатній, справжній вихід вимагає або очікування завершення його терміну дії, або ведення списку відкликань на стороні сервера. Саме тому використовують короткі терміни дії та refresh-токен, який можна відкликати.

Чи можна поєднати сесії та JWT?

Так, це поширена практика: access-токен JWT із коротким терміном дії для викликів API та refresh-токен, керований як сесія (збережений і відкличний на стороні сервера), для оновлення access-токена.