5 мин

Что такое JWT? Понятное руководство по JSON Web Tokens

Узнайте, что такое JWT (JSON Web Token), как работают его три части, где он используется и ключевые советы по безопасности, чтобы избежать распространённых ошибок с токенами.

Что такое JWT? Понятное руководство по JSON Web Tokens

JWT простыми словами

JWT (JSON Web Token) — это компактная, URL-безопасная строка, которая представляет набор информации (обычно о пользователе или сессии) и может передаваться между системами. Вы часто увидите её как длинное значение, начинающееся с eyJ..., отправляемое в HTTP-заголовке, например Authorization: Bearer \u003ctoken\u003e.

Зачем вообще нужен токен?

Традиционные логины часто опираются на серверные сессии: вы входите, сервер сохраняет данные сессии и отдаёт браузеру cookie с ID сессии. Каждый запрос включает эту cookie, и сервер смотрит запись сессии.

С аутентификацией на основе токенов сервер может избежать хранения состояния для каждого запроса пользователя. Клиент держит токен (например, JWT) и прикладывает его к вызовам API. Это популярно для API, потому что:

  • хорошо работает между множеством сервисов (API gateway, микросервисы)
  • подходит для мобильных приложений и одностраничных приложений (SPA), которые напрямую вызывают API
  • снижает необходимость в общем хранилище сессий между серверами

Важное уточнение: «stateless» не означает «никаких серверных проверок». Многие реальные системы всё ещё дополнительно проверяют токены на предмет статуса пользователя, ротации ключей или механизмов отзыва.

Аутентификация vs авторизация (простыми словами)

  • Аутентификация отвечает: Кто вы? (Вы входите и доказываете свою личность.)
  • Авторизация отвечает: Что вам разрешено делать? (Чтение счетов, редактирование проектов, доступ к админке и т.д.)

JWT часто несут в себе доказательство аутентификации (вы вошли) и подсказки для авторизации (роли, права, scope), — но сервер всё равно должен применять правила авторизации.

Где встречаются JWT

JWT обычно используются как access tokens в:

  • веб-API
  • SPA
  • мобильных приложениях
  • системах с OAuth 2.0 или OpenID Connect (OIDC)

Структура JWT: header, payload и signature

JWT — компактная строка из трёх частей, каждая base64url-encoded и разделённая точками:

header.payload.signature

Пример (редактировано):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxNzAwMDAwMDAwfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c…

1) Header

Header описывает, как был создан токен — главным образом алгоритм подписи (например, HS256, RS256/ES256) и тип токена.

Обычные поля:

  • typ: часто "JWT" (часто игнорируется на практике)
  • alg: алгоритм подписи
  • kid: идентификатор ключа, помогающий выбрать нужный ключ при ротации

Заметка по безопасности: не доверяйте header слепо. Применяйте allowlist алгоритмов, которые вы действительно используете, и не принимайте alg: "none".

2) Payload

Payload содержит "claims" — поля о пользователе и контексте токена: для кого он, кто выпустил и когда истекает.

Важно: JWT по умолчанию не шифруются. Base64url делает токен безопасным для URL; он не скрывает данные. Любой, у кого есть токен, может декодировать header и payload.

Поэтому не храните в JWT секреты (пароли, API-ключи) или чувствительные персональные данные.

3) Signature

Подпись создаётся путём подписания header + payload с использованием ключа:

  • HS256: общий секрет для подписи и проверки
  • RS256/ES256: приватный ключ подписывает; публичный ключ проверяет

Подпись обеспечивает целостность: сервер убеждается, что токен не был изменён и выпущен доверенным подписантом. Подпись не обеспечивает конфиденциальность.

Размер токена

Поскольку JWT включает header и payload в каждом запросе, где он отправляется, большие токены увеличивают трафик и нагрузку. Держите claims минимальными и предпочитайте идентификаторы вместо громоздких данных.

Payload и claims: что можно и чего нельзя хранить

Проектируйте claims уверенно
Планируйте роли, аудитории, издателей и правила истечения до генерации кода.

Claims делятся на две категории: зарегистрированные (стандартизированные имена) и пользовательские (поля вашего приложения).

Частые зарегистрированные claims

  • iss (issuer): кто создал токен
  • sub (subject): о ком токен (часто ID пользователя)
  • aud (audience): для кого предназначен токен (например, конкретное API)
  • exp (expiration time): когда токен должен перестать приниматься
  • iat (issued at): когда токен создан
  • nbf (not before): токен не должен приниматься до этого времени

Пользовательские claims: держите их минимальными

Включайте только то, что реально нужно принимающему сервису для принятия решения об авторизации.

Хорошие примеры:

  • стабильный внутренний идентификатор пользователя (user_id)
  • небольшой набор ролей/прав (только если вы можете их поддерживать в актуальном состоянии)
  • tenant/organization ID для мультиарендных приложений

Избегайте "удобных" claims с копированием профиля: они раздувают токен, быстро устаревают и увеличивают последствия утечки.

Что никогда не стоит помещать в JWT payload

Поскольку payload читаем, не храните:

  • пароли, API-ключи, refresh-токены или любые секреты
  • платежные данные, номера документов или чувствительные персональные данные
  • всё, что вы не хотели бы увидеть в браузере, прокси или логах

Если нужна чувствительная информация, храните её на сервере и в токен кладите только ссылку (ID), либо используйте зашифрованный формат токена (JWE) при необходимости.

Как работает подпись (и что она гарантирует)

Подпись — это не шифрование.

  • Подпись похожа на опечатанный конверт: можно прочитать письмо, но можно проверить, не меняли ли его содержимое.
  • Шифрование похоже на запирание письма: читать может только тот, у кого есть ключ.

При выпуске JWT сервер подписывает закодированные header + payload. При предъявлении токена позже сервер пересчитывает подпись и сравнивает. Если кто-то изменит хоть один символ (например, "role":"user" на "role":"admin"), верификация упадёт и токен отвергнут.

JWT vs OAuth, OpenID Connect и типы токенов

JWT — это формат токена. OAuth 2.0 и OpenID Connect (OIDC) — протоколы, описывающие, как приложения запрашивают, выдают и используют токены.

OAuth 2.0 — access/refresh токены

OAuth 2.0 в основном про авторизацию: дать приложению доступ к API от имени пользователя без передачи пароля.

  • Access token: предъявляется API, чтобы доказать разрешение; может быть JWT или opaque
  • Refresh token: долгоживущий токен для получения новых access-токенов

Access-токены обычно короткоживущие (минуты). Короткий срок ограничивает ущерб при утечке.

OpenID Connect (OIDC) и ID-токены

OIDC добавляет аутентификацию (подтверждение личности) поверх OAuth 2.0 и вводит ID token, который обычно является JWT.

  • ID token: для клиентского приложения — чтобы подтвердить личность пользователя
  • Access token: для API — чтобы авторизовать запросы

Правило: не используйте ID token для вызова API.

Если нужно больше примеров потоков, см. /blog/jwt-authentication-flow.

Обычный поток аутентификации с JWT

Избавьтесь от шаблонного кода JWT
Пусть Koder.ai возьмёт на себя рутинную связку, а вы сосредоточьтесь на ротации ключей и политиках.

Типичный поток выглядит так:

1) Вход

Пользователь входит (email/password, SSO и т.д.). При успехе сервер создаёт JWT (часто это access token) с базовыми claims, такими как subject и expiration.

2) Выдача токена

Сервер подписывает токен и возвращает его клиенту (веб-приложение, мобильное приложение или другой сервис).

3) Вызовы API

Для защищённых эндпоинтов клиент включает JWT в заголовок Authorization:

Authorization: Bearer \u003cJWT\u003e

4) Верификация

Перед обслуживанием запроса API обычно проверяет:

  • подпись (целостность + надёжный издатель)
  • exp (не просрочен)
  • iss (ожидаемый issuer)
  • aud (предназначен для этого API)

Если все проверки проходят, API считает пользователя аутентифицированным и применяет правила авторизации (например, уровень доступа к записям).

5) Небольшая заметка про дрейф часов

Поскольку часы на системах расходятся, многие системы допускают небольшой clock skew при проверке временных claims, таких как exp и nbf. Держите допуск небольшим, чтобы не увеличивать фактическое время жизни токена больше задуманного.

Где безопасно хранить JWT

Выбор места хранения меняет, какие атаки возможны и насколько легко можно повторно использовать токен.

Браузер: память vs localStorage vs cookies

Хранение в памяти (рекомендуется для SPA) — держите access-токен в JS-памяти. Он очищается при перезагрузке и снижает риск «взять позже», но XSS во время выполнения страницы всё ещё может его прочитать. Используйте короткоживущие access-токены и поток обновления.

localStorage/sessionStorage просты, но рискованы: любой XSS может вытянуть токены. Если используете, профилактика XSS обязателна (CSP, экранирование, проверка зависимостей), и держите токены короткоживущими.

Secure cookies (часто самый безопасный выбор для веба) — храните токены в HttpOnly cookie, чтобы JavaScript не мог их прочитать. Минус — риск CSRF, так как браузер автоматически прикладывает cookie.

Если используете cookies, установите:

  • HttpOnly
  • Secure (только по HTTPS)
  • SameSite=Lax или SameSite=Strict (иногда для кросс-сайтовых потоков нужен SameSite=None; Secure)

Также рассмотрите CSRF-токены для запросов, изменяющих состояние.

Мобильные приложения: используйте защищённое хранилище ОС

На iOS/Android храните токены в безопасном хранилище платформы (Keychain / Keystore). Избегайте простых файлов или настроек. Если угроза включает рутованные/джейлбрейкнутые устройства, предполагайте, что извлечение возможно — полагайтесь на короткоживущие токены и серверные механизмы контроля.

Принцип наименьших привилегий

Ограничивайте возможности токена: минимальные scope/claims, короткое время жизни access-токенов, и избегайте вложения чувствительных данных.

Типичные ошибки безопасности JWT, которых стоит избегать

JWT удобны, но многие инциденты происходят из-за предсказуемых ошибок. Относитесь к JWT как к наличным деньгам: кто получил — тот может потратить.

1) Слишком длительный срок жизни

Если токен живёт дни или недели, утечка даёт атакующему всё это окно. Предпочитайте короткоживущие access-токены (минуты) и обновляйте их через безопасный механизм. Для «запомнить меня» используйте refresh-токены и серверные проверки.

2) Отсутствие проверок issuer и audience

Подпись недостаточна. Проверяйте iss и aud, валидируйте временные claims, такие как exp и nbf.

3) Доверие декодированному payload

Декодирование — это не верификация. Всегда проверяйте подпись на сервере и применяйте авторизационные политики серверной стороны.

4) Путаница с алгоритмами и ключами

  • Не принимайте любой алгоритм из header. Делайте allowlist.
  • Не смешивайте симметричные ключи (HS256) и асимметричные (RS256/ES256).
  • Снижайте blast radius, разделяя ключи между окружениями и проводя ротацию.

5) Утечка токенов через URL, логи и referrer

Избегайте размещения JWT в query-параметрах. Они могут попасть в историю браузера, логи, аналитические сервисы и referrer-заголовки.

Используйте Authorization: Bearer ... вместо этого.

6) Отсутствие плана ротации и отзыва ключей

Предполагайте, что ключи и токены могут утечь. Проводите ротацию signing-ключей, используйте kid для плавной ротации и имейте стратегию отзыва (короткие сроки жизни + возможность отключать аккаунты/сессии). Для советов по хранению смотрите /blog/where-to-store-jwts-safely.

Когда стоит использовать JWT (и когда нет)

От сборки до деплоя
Разверните и хостьте приложение на JWT напрямую с поддержкой кастомных доменов.

JWT полезны, но не всегда лучший выбор. Вопрос: приносит ли вам пользу самодостаточный токен, который можно проверить без обращения к базе при каждом запросе?

Подходящие случаи для JWT

  • Статeless API в масштабе: локальная проверка (подпись + expiry) без запроса сессии на каждый запрос
  • Множество сервисов / микросервисы: общие правила валидации и публичные ключи
  • SPA и мобильные приложения: клиенты вызывают API напрямую
  • Короткоживущие access-токены: уменьшают ущерб при утечке

Когда JWT — плохой выбор

  • Требуется мгновенный отзыв: сессии проще, если нужно «выйти везде сейчас» без дополнительной инфраструктуры
  • Нужно хранить чувствительные данные: обычные JWT подписываются, но не шифруются
  • Долгоживущие токены: они дорогие для безопасности и стоят того, чтобы их не использовать

Для традиционных серверно-рендеренных приложений, где важно простое инвалидирование, серверные сессии с HttpOnly cookies чаще проще и безопаснее.

Короткий чек-лист для решения

Выбирайте JWT, если вам нужна статeless-проверка между сервисами и вы можете держать токены короткоживущими.

Избегайте JWT, если нужна мгновенная отзывность, вы собираетесь помещать чувствительные данные в токен или можете использовать cookie-сессии без неудобств.

Практический чек-лист и FAQ

Чек-лист валидации (что проверять каждый раз)

  1. Подпись валидна

Проверяйте правильный ключ и ожидаемый алгоритм. Отклоняйте неверные подписи — никаких исключений.

  1. exp (срок действия)

Убедитесь, что токен не просрочен.

  1. nbf (not before)

Если присутствует, убедитесь, что токен не используется раньше времени.

  1. aud (audience)

Подтвердите, что токен предназначен для вашего API/сервиса.

  1. iss (issuer)

Подтвердите, что токен выпущен ожидаемым издателем.

  1. Sanity checks (рекомендуется)

Проверяйте формат токена, максимальный размер и отвергайте неожиданные типы claims, чтобы снизить риск пограничных ошибок.

Выбор HS256 vs RS256/ES256

  • HS256 (симметричный ключ): один общий секрет для подписи и проверки.

    • Подходит для: единого приложения/API, управляемого одной командой.
    • Минус: любой, у кого есть секрет, может и подписывать токены.
  • RS256 / ES256 (асимметричные ключи): приватный ключ подписывает; публичный ключ проверяет.

    • Подходит для: множества сервисов, которые проверяют токены; распространение публичного ключа не даёт возможности подписывать.
    • Операционно: ротация часто безопаснее, потому что подписывает только приватный ключ.

Правило: если более одной независимой системы должна проверять токены (или вы не полностью доверяете каждому верификатору), предпочитайте RS256/ES256.

Мониторинг и логирование (без утечек токенов)

  • Не логируйте сырые токены (в заголовках, cookie, query-строках).
  • Если нужен корелляционный идентификатор, логируйте фингерпринт токена (например, хеш) или безопасную метаинформацию (iss, aud, user ID только если политика позволяет).
  • Следите за аномалиями: неудачные подписи, всплески просроченных токенов, необычные audience/issuer и подозрительные паттерны обновления.

FAQ

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

Не по умолчанию. Большинство JWT подписаны, но не зашифрованы — содержимое читаемо при наличии токена. Используйте JWE или не храните чувствительные данные в JWT.

Можно ли отозвать JWT?

Сложно, если вы полагаетесь только на самодостаточные access-токены. Распространённые подходы: короткоживущие access-токены, deny-list в критичных случаях, или refresh-токены с ротацией.

Какой должен быть срок exp?

Как можно короче, при условии приемлемого UX и архитектуры. Многие API используют минуты для access-токенов и refresh-токены для продолжительных сессий.

Быстрее создавать приложения с защитой JWT с помощью Koder.ai

Если вы внедряете JWT-аутентификацию в новый API или SPA, много работы повторяется: подключение middleware, проверка iss/aud/exp, установка флагов cookie и исключение обработки токенов в логах.

С Koder.ai вы можете быстро прототипировать веб-приложение (React), бэкенд (Go + PostgreSQL) или Flutter-приложение через чат-ориентированный рабочий процесс — затем итеративно планировать, использовать снимки и откаты при отладке безопасности и экспортировать исходный код, когда будете готовы. Это практичный способ ускорить реализацию JWT-аутентификации, сохраняя контроль над логикой верификации, стратегией ротации ключей и настройками деплоя (включая кастомные домены).

FAQ

Что такое JWT и куда я обычно его отправляю?

JWT (JSON Web Token) — это компактная, URL-безопасная строка, которая несёт «claims» (поля данных) и может быть проверена сервером. Обычно её отправляют в API-запросах через:

  • Authorization: Bearer <token>

Главная идея: сервер может проверить целостность токена (по подписи) без необходимости хранить сессию для каждого запроса.

Чем JWT-аутентификация отличается от серверных сессий?

Аутентификация через сессии обычно хранит состояние на сервере (запись сессии, идентифицируемая cookie/ID сессии). При JWT-аутентификации клиент прикладывает подписанный токен к каждому запросу, а API его валидирует.

JWT популярны для API и распределённых приложений, потому что проверку можно выполнить локально, уменьшая потребность в общем хранилище сессий.

«Бессерверность» не означает отсутствие серверных проверок: часто добавляют deny-list, проверки статуса пользователя или обработку ротации ключей.

Какие три части у JWT (header, payload, signature)?

JWT состоит из трёх частей Base64URL-кодированных и разделённых точками:

  • header.payload.signature

Header описывает алгоритм подписи, payload содержит claims (например, sub, exp, aud), а подпись позволяет серверу обнаружить подделку.

JWT зашифрован и можно ли читать его содержимое?

Нет. Стандартные JWT обычно подписаны, но не зашифрованы.

  • Подпись подтверждает целостность и происхождение (не была ли изменена).
  • Любой, у кого есть токен, может Base64URL-декодировать header и payload и прочитать содержимое.

Если нужна конфиденциальность, используйте JWE (шифрованные токены) или храните чувствительные данные на сервере, оставляя в токене только ссылку/ID.

Что гарантирует подпись JWT — и чего она не гарантирует?

Подпись позволяет серверу убедиться, что токен не был изменён и его выпустил доверенный подписант.

Она не даёт:

  • конфиденциальности содержимого;
  • гарантии, что пользователь всё ещё активен (если вы это не проверяете);
  • немедленной отмены токена до exp.

Относитесь к токену как к учетным данным: если он скомрометирован, его можно воспроизвести до истечения срока действия.

Что такое `alg` и `kid` в заголовке JWT и почему это важно?

alg указывает алгоритм, использованный для подписи (например, HS256 или RS256). kid — идентификатор ключа, помогающий подобрать правильный ключ при ротации.

Рекомендации по безопасности:

  • Делайте allowlist ожидаемых алгоритмов; не принимайте произвольные alg.
  • Никогда не принимайте alg: "none".
  • Не позволяйте недоверенному kid приводить к небезопасному поиску ключа.
Какие claims стоит включать в payload JWT?

Начните со стандартных зарегистрированных claims и держите собственные поля минимальными.

Частые зарегистрированные claims:

  • iss (issuer) — кто выпустил токен
  • sub (subject) — субъект / идентификатор пользователя
  • aud (audience) — для кого предназначен токен (API)
  • exp (expiration) — время окончания действия
  • iat (issued at) — время выпуска
  • nbf (not before) — токен не пригоден до этого времени

Избегайте хранения секретов и чувствительных персональных данных в payload: всё, что в токене — читаемо при утечке.

Как соотносятся JWT, OAuth 2.0 и OpenID Connect (access token vs ID token)?

JWT — это формат токена; OAuth 2.0 и OpenID Connect — протоколы.

Типичное соответствие:

  • Access token: для вызова API (может быть JWT или opaque).
  • ID token (OIDC): для клиента, чтобы подтвердить личность (обычно JWT).
  • Refresh token: для получения новых access-токенов (часто opaque и очень чувствителен).

Важно: не используйте ID token для вызова API просто потому, что он «выглядит как JWT».

Где безопасно хранить JWT в браузерном приложении?

Для браузерных приложений распространённые варианты хранения:

  • В памяти: рекомендуется для SPA — токен хранится в JS-памяти. Очищается при перезагрузке, но XSS во время работы страницы всё ещё может украсть его. Сочетайте с коротким временем жизни access-токена и безопасным механизмом обновления.
  • localStorage / sessionStorage: удобны, но уязвимы для XSS. Если используете их, предотвращение XSS — критично (CSP, экранирование вывода, контроль зависимостей), и держите токены короткоживущими.
  • HttpOnly Secure cookies: часто самый безопасный вариант для веба — JS не может их прочитать. Минус — риск CSRF, поскольку браузер автоматически прилагает cookie. Используйте HttpOnly, Secure и SameSite и при необходимости CSRF-токены для изменяющих состояние запросов.

В любом случае держите access-токены короткоживущими и минимизируйте права.

Какие проверки должен выполнять API при валидации JWT?

Минимум проверок при валидации JWT:

  • подпись (правильный ключ и allowlisted алгоритм)
  • exp (не истёк)
  • iss (ожидаемый издатель)
  • aud (предназначен для вашего API)
  • nbf (если есть)

Практические дополнения:

  • ограничьте максимальный размер токена
  • отвергайте неожиданные типы claims
  • допуск небольшого дрейфа времени (clock skew) чтобы компенсировать расхождения часов

Похожие статьи