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 у cookieHttpOnlyскасовує цю перевагу 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-токена.