Атаки на JWT: alg:none, key confusion, header injection

JWT (JSON Web Token) используется как компактный формат передачи утверждений между сторонами и опирается на криптографическую подпись для проверки целостности. В JavaScript-экосистеме работа с JWT часто реализуется через библиотеку Jose, которая поддерживает JWS (подписи), JWE (шифрование) и JWK (ключи).

Критическая особенность JWT заключается в том, что безопасность системы определяется не самим форматом токена, а корректностью обработки заголовка (header), выбора алгоритма подписи и управления ключами.


Уязвимость alg:none

В спецификации JWT допускается указание алгоритма подписи в заголовке:

{
  "alg": "HS256",
  "typ": "JWT"
}

Некоторые реализации исторически поддерживали значение:

{
  "alg": "none"
}

Механика проблемы

При значении alg: none подпись отсутствует. Уязвимости возникают в случаях, когда:

  • сервер доверяет полю alg из токена
  • не фиксируется допустимый список алгоритмов
  • библиотека или обёртка пропускает проверку подписи

Типовой сценарий сбоя логики проверки

  • токен декодируется
  • извлекается alg
  • подпись не проверяется, если alg === "none"
  • payload принимается как валидный

Защитный подход

В безопасных реализациях, включая современные версии Jose:

  • список алгоритмов задаётся явно
  • none исключается на уровне конфигурации
  • проверка подписи выполняется независимо от header

Key Confusion (путаница ключей)

Атака key confusion возникает из-за неправильной интерпретации типа ключа при верификации подписи.

Суть проблемы

JWT может быть подписан:

  • симметричным ключом (HMAC, HS256)
  • асимметричным ключом (RSA/EC, RS256, ES256)

Ошибка возникает, когда:

  • система ожидает RSA-подпись
  • но принимает HMAC-проверку с публичным ключом

Механика атаки

  1. Сервер использует RS256 (RSA)
  2. Проверка выполнена с публичным ключом
  3. Злоумышленник подменяет алгоритм на HS256
  4. В качестве HMAC-ключа используется публичный RSA-ключ
  5. Подпись становится валидируемой некорректно

Причина возникновения

  • автоматическое определение алгоритма из JWT header
  • отсутствие жёсткой привязки к ожидаемому типу ключа
  • универсальные функции verify без ограничения alg

Поведение в Jose

В библиотеке Jose контроль должен быть явным:

  • algorithms задаются при верификации
  • ключ передаётся строго соответствующего типа
  • несоответствие алгоритма приводит к ошибке

Header Injection (инъекция в заголовок JWT)

JWT header является JSON-структурой, которая передаётся в base64url-кодировке. Ошибки возникают, когда данные из header используются в логике проверки без строгой валидации.

Основные векторы злоупотребления

1. Подмена параметра alg

Если система динамически выбирает алгоритм из header:

{
  "alg": "HS256",
  "kid": "key-id-1"
}

возможна подмена алгоритма на несовместимый или менее безопасный.


2. Использование kid (Key ID) для инъекций

Поле kid предназначено для выбора ключа из хранилища:

{
  "alg": "RS256",
  "kid": "../. ./evil-key"
}

Ошибки возникают при:

  • файловом поиске ключа по пути
  • отсутствии фильтрации kid
  • динамическом построении пути к ключу

Это может приводить к:

  • чтению произвольных файлов
  • подстановке контролируемого ключа
  • обходу проверки подписи

3. Встраивание небезопасных метаданных

Некорректные реализации могут использовать header для:

  • выбора алгоритма
  • выбора источника ключей
  • определения режима верификации

Любая зависимость логики безопасности от header создаёт поверхность атаки.


Ошибки интеграции с библиотекой Jose

При использовании Jose ключевые проблемы возникают не в криптографии, а в конфигурации.

1. Отсутствие фиксации алгоритма

Опасная модель:

  • алгоритм берётся из токена

Безопасная модель:

  • алгоритм задан явно в verify

2. Смешивание типов ключей

  • RSA ключ используется как HMAC
  • EC ключ интерпретируется как симметричный

3. Динамическая загрузка ключей без контроля

  • kid напрямую влияет на путь
  • отсутствует whitelist ключей
  • нет валидации структуры идентификатора

Практика безопасной валидации JWT в Jose

Корректная модель проверки строится вокруг принципа фиксированной конфигурации:

  • жёстко заданный алгоритм (например, только RS256)
  • явный набор допустимых ключей
  • запрет использования none
  • контроль структуры header до криптографической проверки

Архитектурные причины уязвимостей JWT

Большинство проблем возникает из-за архитектурных решений:

  • доверие данным из токена
  • смешивание ответственности (логика + криптография)
  • динамическая конфигурация безопасности
  • отсутствие строгой типизации ключей

JWT сам по себе не является небезопасным механизмом; уязвимости формируются на уровне обработки header и управления ключами.