Почему нельзя доверять заголовку alg без ограничений

В спецификациях JOSE (JSON Object Signing and Encryption) и в экосистеме JWT ключевую роль играет заголовок JWS, в частности поле alg, определяющее алгоритм подписи. Именно оно сообщает библиотеке и проверяющей стороне, как интерпретировать подпись токена: HS256, RS256, ES256 и другие варианты.

На практике это поле часто воспринимается как техническая метка, однако его неконтролируемое доверие приводит к целому классу критических уязвимостей. Библиотека jose в JavaScript реализует строгую модель проверки, но при неправильной интеграции разработчиком безопасность легко нарушается.

Алгоритм как часть проверяемых данных, а не источник истины

Ключевая ошибка многих реализаций JWT-систем заключается в том, что значение alg используется для выбора механизма верификации напрямую из входящего токена.

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

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

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

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

Классическая атака: algorithm confusion

Исторически одной из самых опасных проблем JWT стала путаница между симметричными и асимметричными алгоритмами.

  • HS256 использует общий секрет (HMAC)
  • RS256 использует пару ключей (RSA: приватный/публичный)

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

  1. Ожидает RS256 (проверка публичным ключом)
  2. Но принимает alg: HS256 из токена
  3. Использует публичный ключ как HMAC-секрет

В результате публичный ключ начинает выступать как секретный ключ HMAC, что делает подпись полностью подделываемой.

Это не гипотетический сценарий, а исторически массовая уязвимость реальных систем.

Опасность алгоритма none

Еще один критический режим связан с alg: none. Он предназначался для сценариев без подписи, но во многих реализациях стал источником обхода аутентификации.

Если библиотека или обвязка:

  • не запрещает none
  • или допускает его при неверной конфигурации

то токен может быть принят без криптографической проверки.

В современных версиях jose такие сценарии блокируются по умолчанию, но проблема часто возникает на уровне архитектуры приложения, а не библиотеки.

Почему нельзя использовать alg из токена для выбора ключа

Заголовок JWS не только определяет алгоритм, но в некоторых реализациях косвенно влияет на выбор ключа. Это приводит к более сложным атакам:

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

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

Правильная модель работы с jose в JavaScript

Библиотека jose реализует безопасный подход, при котором алгоритмы явно задаются разработчиком.

Пример проверки JWT:

import { jwtVerify, createRemoteJWKSet } from 'jose'

const JWKS = createRemoteJWKSet(new URL('https://example.com/.well-known/jwks.json'))

const { payload } = await jwtVerify(token, JWKS, {
  algorithms: ['RS256']
})

Здесь ключевой момент заключается в том, что:

  • список допустимых алгоритмов задается явно
  • значение alg из токена не влияет на выбор допустимых методов проверки
  • даже если токен указывает другой алгоритм, он будет отклонен

Защита от смешивания алгоритмов

Системная защита должна учитывать несколько принципов:

  • алгоритмы фиксируются на уровне конфигурации, а не входных данных
  • симметричные и асимметричные схемы никогда не должны пересекаться в одной точке принятия решений
  • публичные ключи не могут использоваться как секреты HMAC
  • любые значения из заголовка JWS рассматриваются как недоверенные

В jose это реализуется через явное указание допустимых алгоритмов и строгую проверку соответствия ключей.

Почему доверие к alg ломает модель безопасности JWT

JWT часто ошибочно воспринимается как “защищенный JSON”, тогда как его безопасность полностью определяется криптографической проверкой подписи. Если атакующий получает возможность влиять на выбор алгоритма, он фактически получает контроль над механизмом проверки целостности.

Это приводит к фундаментальному нарушению модели доверия:

  • подпись перестает быть гарантией подлинности
  • проверка превращается в формальность
  • система начинает доверять данным, которые сама должна защищать

Именно поэтому поле alg должно рассматриваться как вспомогательная метаинформация, а не как управляющий параметр безопасности.

Архитектурный принцип изоляции криптографии

Корректная архитектура работы с JOSE в JavaScript строится вокруг изоляции:

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

Любое отклонение от этой модели приводит к тому, что криптография становится зависимой от входных данных, что принципиально недопустимо в системах аутентификации.