Информационная безопасность

JWT, OAuth 2.0, OpenID Connect

«Войти через Google» - это не просто кнопка. За ней стоит OAuth 2.0 + OIDC: протоколы, которые позволяют миллиарду приложений не хранить пароли пользователей. JWT подписывают миллиарды API-запросов в секунду. Одна ошибка в реализации - alg:none атака, reuse refresh token, отсутствие aud проверки - и весь механизм рассыпается.

  • **Google Sign-In / GitHub OAuth:** все используют OIDC + Authorization Code + PKCE. Миллиарды авторизаций в день
  • **Auth0, Okta, Keycloak:** managed identity providers - реализуют полный OAuth 2.0 + OIDC стек за вас
  • **JWT в микросервисах:** API Gateway выдаёт JWT, каждый сервис верифицирует локально без обращения к auth-сервису

JWT: структура и уязвимости

**JWT (JSON Web Token)** - это три base64url-закодированных части, разделённых точками: `header.payload.signature`. Сервер подписывает payload своим ключом, клиент хранит токен и отправляет его в каждом запросе. Сервер проверяет подпись - не нужно лезть в БД за сессией.

**JWT vs Sessions:** JWT stateless - нет хранения на сервере, масштабируется горизонтально. Сессии stateful - можно мгновенно инвалидировать. Для access tokens - JWT (короткий TTL). Для refresh tokens - stateful (в Redis/БД с возможностью отзыва).

Почему в JWT payload нельзя хранить пароль пользователя, даже если токен подписан?

OAuth 2.0 Flows: Authorization Code, PKCE

«Войти через Google» - это OAuth 2.0. Суть: пользователь даёт приложению доступ к своим ресурсам у провайдера (Google, GitHub), не передавая пароль. Приложение получает **access token** - временный ключ с ограниченными правами. Если token утечёт - он даст только те права, что разрешил пользователь.

**Implicit Flow устарел** (RFC 9700, 2025). Раньше SPA использовали его: token прямо в URL-фрагменте. Проблема: token в URL попадает в историю браузера, Referer headers, логи. Теперь стандарт - Authorization Code + PKCE даже для SPA.

Зачем нужен параметр `state` в OAuth Authorization Code flow?

OpenID Connect: аутентификация поверх OAuth

OAuth 2.0 решает **авторизацию**: «дай приложению доступ к моим данным». Но он не говорит кто этот пользователь. **OpenID Connect (OIDC)** - тонкий слой поверх OAuth 2.0, который добавляет аутентификацию: вместе с access token провайдер возвращает **ID token** - JWT с информацией о пользователе (sub, email, name).

Приложение получило ID Token от Google. Проверку какого claim ОБЯЗАТЕЛЬНО нужно сделать помимо подписи и exp?

Token Management: refresh, revocation

Access token живёт 15 минут - пользователю не нужно логиниться каждые 15 минут. **Refresh token** - долгоживущий токен (дни, недели) для получения новых access tokens без повторного входа. Но чем дольше живёт токен, тем опаснее его компрометация. **Token rotation** решает это: каждый refresh token одноразовый.

**Silent refresh:** SPA обновляет access token заранее, до истечения. Схема: за 1 минуту до exp делать POST /auth/refresh с httpOnly cookie. Пользователь не замечает переходов.

Что должен делать сервер при обнаружении reuse refresh token (кто-то использовал уже использованный токен)?

JWT + OAuth 2.0 + OIDC

  • **JWT:** header.payload.signature - payload виден всем (base64), signature гарантирует целостность; защититься от alg:none - строгий whitelist алгоритмов
  • **OAuth 2.0:** делегированная авторизация без передачи пароля; Authorization Code + PKCE для SPA; state защищает от CSRF
  • **OIDC:** аутентификация поверх OAuth - ID Token с sub, email; обязательно проверять aud и подпись через JWKS URI провайдера
  • **Token Management:** access token в памяти (15 мин), refresh token в httpOnly cookie (30 дней) с rotation; reuse detection инвалидирует все сессии

Связанные темы

JWT и OAuth строятся на криптографии и работают в контексте более широких уязвимостей.

  • Аутентификация и авторизация — Концептуальные основы: кто такой пользователь и что ему разрешено
  • Хеширование и цифровые подписи — JWT signature использует HMAC и RSA/ECDSA
  • OWASP Top 10 — Broken Authentication - вторая угроза OWASP; JWT реализует безопасную auth

Вопросы для размышления

  • Почему access token должен жить 15 минут, а не 24 часа, даже если это неудобно?
  • В чём разница между OAuth 2.0 и OIDC в контексте вопроса 'кто этот пользователь'?
  • Почему хранить refresh token в localStorage небезопаснее чем в httpOnly cookie, даже если CSRF-защита выключена?

Связанные уроки

  • net-64-api-gateway
JWT, OAuth 2.0, OpenID Connect

0

1

Войти