Алгоритмическая путаница (alg confusion) в JWT возникает в момент,
когда система некорректно обрабатывает параметр alg в
заголовке токена и допускает подмену алгоритма подписи. Это одна из
наиболее критичных ошибок реализации проверки JWT, особенно в связке
симметричных (HMAC) и асимметричных (RSA/ECDSA) схем.
JWT состоит из трёх частей: заголовка, полезной нагрузки и подписи.
Заголовок обычно выглядит так:
{
"alg": "RS256",
"typ": "JWT"
}
Полезная нагрузка содержит утверждения (claims), например:
{
"sub": "user123",
"role": "admin",
"iat": 1710000000
}
Подпись формируется на основе заголовка и payload с использованием секретного ключа или приватного ключа, в зависимости от алгоритма.
Ключевая деталь: поле alg не просто информативное —
многие библиотеки используют его для выбора алгоритма проверки
подписи.
Алгоритмическая путаница возникает, когда сервер доверяет значению
alg из самого JWT и использует его при верификации.
Типичный сценарий уязвимости:
RS256 (RSA, асимметричная
криптография)alg на HS256 (HMAC,
симметричный алгоритм)В результате публичный ключ превращается в секрет HMAC, и атакующий может самостоятельно подписывать токены.
Предположим, сервер принимает JWT и использует библиотеку, которая автоматически выбирает алгоритм из заголовка:
const jwt = header + "." + payload;
const signature = HMAC(publicKey, jwt); // ошибка логики
Если атакующий подменяет:
{
"alg": "HS256"
}
и подписывает токен с использованием известного публичного ключа как секрет:
HMAC(publicKey, data)
сервер успешно проверяет подпись, так как делает то же самое.
Проблема возникает из-за смешивания двух моделей:
Если библиотека не фиксирует алгоритм на серверной стороне, она может переключиться на HS256 автоматически.
Библиотека Jsrsasign предоставляет низкоуровневые криптографические функции и инструменты для работы с JWT, включая строгую проверку алгоритмов.
Пример проверки JWT с RS256:
const KJUR = require('jsrsasign');
const publicKey = `-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----`;
const jwt = "header.payload.signature";
const isValid = KJUR.jws.JWS.verifyJWT(jwt, publicKey, {
alg: ["RS256"]
});
Ключевой момент: явное указание допустимых алгоритмов.
Следующий подход приводит к alg confusion:
KJUR.jws.JWS.verifyJWT(jwt, publicKey, {
alg: ["HS256", "RS256"] // опасная практика
});
или ещё хуже — отсутствие ограничения:
KJUR.jws.JWS.verifyJWT(jwt, publicKey);
В таких случаях библиотека может принять алгоритм из заголовка без валидации контекста доверия.
Безопасная архитектура всегда фиксирует алгоритм вне токена:
const isValid = KJUR.jws.JWS.verifyJWT(jwt, publicKey, {
alg: ["RS256"],
verifyAt: KJUR.jws.IntDate.getNow()
});
Дополнительно важно:
alg из заголовка как источнику истиныАлгоритмическая путаница часто появляется при переходе:
Если старый код остаётся совместимым с несколькими алгоритмами, сервер может продолжать принимать HS256-токены, используя публичный ключ как секрет.
Jsrsasign позволяет разобрать токен до проверки:
const parsed = KJUR.jws.JWS.parse(jwt);
console.log(parsed.headerObj.alg);
На этом этапе можно принудительно отклонять неожиданные значения:
if (parsed.headerObj.alg !== "RS256") {
throw new Error("Недопустимый алгоритм");
}
Атакующий может модифицировать только заголовок:
{
"alg": "HS256",
"typ": "JWT"
}
При этом payload остаётся неизменным, а подпись пересчитывается под HMAC.
Если сервер не фиксирует алгоритм — проверка проходит успешно.
Слабые реализации часто допускают:
В корректной модели:
Jsrsasign позволяет строить строгую модель проверки:
function verifyToken(jwt, publicKey) {
const header = KJUR.jws.JWS.parse(jwt).headerObj;
if (header.alg !== "RS256") {
return false;
}
return KJUR.jws.JWS.verifyJWT(jwt, publicKey, {
alg: ["RS256"]
});
}
Дополнительно может применяться контроль ключевого типа:
Алгоритмическая путаница чаще всего появляется в:
Особенно опасны ситуации, где:
Основная проблема alg confusion — это не криптографическая уязвимость, а ошибка доверия:
JWT становится безопасным только тогда, когда алгоритм определяется системой, а не токеном.
Библиотека поддерживает множество алгоритмов:
Но безопасность зависит от того, ограничен ли список допустимых алгоритмов:
alg: ["RS256"]
Любое расширение списка увеличивает поверхность атаки.
Строгая схема работы с JWT обычно включает:
algJsrsasign в этой модели выступает как криптографический слой, а не как логика принятия решений.
Типичная корректная последовательность:
alg до криптографииЛюбое отклонение от этой последовательности создаёт условия для alg confusion атаки.