JWT (JSON Web Token) — е компактен формат за предаване на данни между страни под формата на JSON обект, защитен с цифров подпис. Токенът може да бъде подписан с HMAC (симетричен ключ) или RSA/ECDSA (асиметрична двойка), което гарантира цялост и автентичност на данните. Според IETF RFC 7519, 2015, JWT се използва в милиони приложения за удостоверяване, сигурен обмен на claims и като формат ID Token в OpenID Connect.
Основни точки
JSON Web Token (JWT) — е отворен стандарт (RFC 7519), който определя компактен и самодостатъчен начин за предаване на информация между страни под формата на JSON обект. Информацията в JWT се нарича claims — твърдения за субекта (потребител) и допълнителни атрибути. Всеки claim е двойка ключ-стойност: идентификатор на потребител, роля, време на изтичане, издател.
JWT се нарича самодостатъчен, защото цялата информация за проверка се съдържа в самия токен. Сървърът не трябва да има достъп до база данни или външно хранилище, за да се увери в валидността на токена — достатъчно е да провери подписа. Това свойство прави JWT идеален за разпределени системи и микросервизна архитектура, където няколко услуги трябва да удостоверяват заявки без общо хранилище за сесии.
Според данни на Auth0, 2025, над 65% от мобилните и уеб приложения използват JWT като основен формат на токен за API удостоверяване, изпреварвайки opaque токените и идентификаторите на сесии.
JWT се състои от три части, разделени с точки: header.payload.signature. Всяка част е Base64url-кодиран JSON. Нека разгледаме всяка част подробно.
Header съдържа две задължителни полета: alg (algorithm — алгоритъм за подпис) и typ (type — тип на токена, винаги „JWT”). Алгоритъмът може да бъде симетричен (HS256 — HMAC с SHA-256) или асиметричен (RS256 — RSA с SHA-256, ES256 — ECDSA с P-256). Асиметричните алгоритми са предпочитани, защото позволяват на клиента да провери подписа без да притежава тайния ключ.
Пример за декодиран header:
{
"alg": "RS256",
"typ": "JWT",
"kid": "key-id-1"
}
Payload съдържа claims — твърдения за субекта. Claims се делят на три типа: регистрирани (iss, sub, aud, exp, nbf, iat, jti), публични (определени от разработчика в IANA Registry) и частни (договорени между страните). sub (subject) — уникален идентификатор на потребител. exp (expiration) — времеви отпечатък за изтичане на токена. iss (issuer) — издател на токена.
{
"sub": "user-abc-123",
"iss": "https://auth.example.com",
"aud": "my-mobile-app",
"exp": 1812345678,
"iat": 1812342078,
"role": "premium_user"
}
Signature се създава чрез прилагане на алгоритъма за подпис върху конкатенацията на header и payload с помощта на таен или частен ключ. Формула: HMACSHA256(base64UrlEncode(header) + „.” + base64UrlEncode(payload), secret) за HMAC, или RSASHA256(...) за асиметричен алгоритъм. Получателят изчислява подписа по същия начин и го сравнява с получения — ако съвпадат, данните не са променени.
Процесът на работа с JWT се състои от две фази: създаване (издаване) на токена от сървъра за удостоверяване и проверка на токена от клиента или сървъра на ресурсите. Сървърът за удостоверяване получава идентификационните данни на потребителя, създава payload с claims и го подписва. Полученият JWT се изпраща на клиента в отговор на заявката за вход или в тялото на отговора на OAuth 2.0 / OpenID Connect.
В мобилните приложения JWT се използва по следния начин: след успешен вход потребителят получава access token в JWT формат. Приложението го съхранява в защитено хранилище (Keychain на iOS, EncryptedSharedPreferences на Android). При всяка заявка към API приложението добавя заглавката Authorization: Bearer <token>. Сървърът на API проверява подписа на JWT, извлича claims и на тяхна основа взема решение за достъп — без достъп до база данни.
Според данни на Google Codelabs, 2025, използването на JWT във Firebase Authentication намалява броя на заявките към сървъра за удостоверяване с 40–60% в сравнение с токените за сесии, тъй като данните се проверяват локално на всяка микрослужба. Това е особено важно в архитектури с високо натоварване, където всяка милисекунда забавяне влияе върху потребителското изживяване. При 50 000 заявки в минута преминаването към JWT може да спести до 10 сървърни инстанции, обработващи introspection заявки.
JWT и Session Token решават една и съща задача — удостоверяване на заявки — но се различават принципно по архитектура. Session Token е случаен идентификационен низ, който препраща към данни за сесията, съхранявани на сървъра (stateful). JWT — самодостатъчен токен, съдържащ всички данни в себе си (stateless).
| Параметър | JWT | Session Token |
|---|---|---|
| Съхранение на данни | Вътре в токена (самодостатъчен) | На сървъра (хранилище за сесии) |
| Мащабиране | Не изисква споделено хранилище | Изисква Redis/DB за множество сървъри |
| Оттегляне на токен | Сложно (нужен е черен списък) | Просто (изтриване на сесия от DB) |
| Размер | Голям (500–2000 байта) | Малък (16–64 байта) |
| Проверка на подпис | Криптографска | Не (сравнение на низове) |
JWT печели в разпределени системи: микрослужбите могат да проверяват токена локално без споделено хранилище. Например, в архитектура с пет микрослужби всяка услуга проверява JWT за 1–2 ms без мрежово извикване, докато session token изисква достъп до централизиран Redis при всяка заявка, добавяйки 10–30 ms забавяне. Въпреки това, JWT е трудно да се оттегли — ако токенът вече е издаден, той е валиден до изтичане. Session Token може лесно да се оттегли чрез изтриване на записа от DB или Redis.
За мобилни приложения комбинираният подход — JWT с кратък живот (15–30 минути) и Refresh Token — дава баланс между производителност и сигурност. JWT се използва за достъп до API, а refresh token (обикновено opaque) за получаване на нови JWT. При компрометиране на JWT нападателят има достъп за 15–30 минути; при компрометиране на refresh token сесията се блокира чрез ротация и откриване на повторна употреба.
Сигурността на JWT зависи от правилната имплементация. Най-честата уязвимост е атаката „alg none”: нападателят променя header на токена на „alg”: „none” и сървърът, без да провери алгоритъма, приема фалшивия токен. Защита: винаги проверявайте, че алгоритъмът в header съответства на очаквания (RS256, ES256), и отхвърляйте токени с alg: none.
Уязвимостите на JWT включват също: слаб таен ключ за HMAC (разбиване за минути), изтичане на частен ключ (подписване на произволни данни от името на сървъра), съхраняване на чувствителни данни в payload (JWT не криптира, само подписва), атака чрез JWK header injection (вмъкване на собствен публичен ключ). Използването на проверени библиотеки — Nimbus JOSE + JWT, jjwt (io.jsonwebtoken), PyJWT — намалява риска от експлоатация на тези уязвимости.
Допълнителна защитна мярка — JWK Thumbprint (RFC 7638): свързване на публичния ключ с токена чрез отпечатък (thumbprint) в header. Ако сървърът съхранява очаквания thumbprint за всеки клиент, атаката JWK header injection става невъзможна — сървърът отхвърля всеки ключ, който не съвпада с регистрирания. OAuth Security Workshop 2025 препоръчва JWK Thumbprint като задължителна защита за всички JWT, използвани във финансови и медицински приложения.
Библиотеката jjwt (auth0/java-jwt) позволява създаване и проверка на JWT в Android приложение за няколко реда. В примера по-долу сървърът генерира токен с sub и role, а клиентът проверява подписа. За сигурно съхранение на тайния ключ на сървъра използвайте променливи на средата или HSM (Hardware Security Module) — съхранението на ключа в код или конфигурационен файл е груба грешка в сигурността.
val secret = "my-256-bit-secret-key-here"
val token = JWT.create()
.withSubject("user-abc-123")
.withIssuer("auth.example.com")
.withClaim("role", "premium_user")
.withExpiresAt(Date(System.currentTimeMillis() + 3600000))
.sign(Algorithm.HMAC256(secret))
// Изпращане на токена на клиента
println("JWT: $token")
fun verifyToken(token: String): Boolean {
return try {
val decoded = JWT.require(Algorithm.HMAC256(secret))
.withIssuer("auth.example.com")
.build()
.verify(token)
// Подписът е валиден, claims извлечени
println("Subject: ${decoded.subject}")
true
} catch (e: Exception) {
println("Token invalid: ${e.message}")
false
}
}
Често задавани въпроси
Не. JWT се подписва, а не се криптира — всеки може да декодира Base64 payload и да прочете данните. Чувствителната информация (пароли, номера на карти, лични данни) трябва да се предава само в криптиран вид чрез JWE (JSON Web Encryption).
Препоръчва се ES256 (ECDSA с P-256) — той осигурява еквивалентно ниво на сигурност като RSA 2048-bit със значително по-малък размер на подписа. За съвместимост с наследени системи е подходящ RS256. HS256 (HMAC) изисква сигурен обмен на таен ключ, което е по-трудно в разпределена архитектура.
JWT не може да бъде оттеглен директно — той е валиден до exp. Решения: използвайте кратък живот (15–30 минути), водете черен списък на оттеглени jti (JWT ID) на сървъра или свържете токените с версия на тайния ключ. Refresh token се оттегля по стандартния начин — чрез изтриване от хранилището.
Bearer token — е концепция: всеки токен, който притежателят (bearer) може да използва за достъп. JWT — е конкретен формат на токен. Bearer token може да бъде JWT или opaque низ. JWT добавя към концепцията Bearer самодостатъчност и криптографска проверка.
Типичен JWT с RS256 подпис заема 500–2000 байта. Ако payload съдържа много персонализирани claims или се използва асиметричен подпис с голям ключ, размерът може да достигне 4–5 KB. Това е значително повече от session token (16–64 байта), което влияе на размера на HTTP заглавките.
Обобщение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също