JWT (JSON Web Token) представляет собой компактный формат передачи утверждений, состоящий из трёх частей: заголовка, полезной нагрузки и подписи. Ключевая идея безопасности JWT — невозможность незаметно изменить содержимое токена без знания секретного ключа или приватного ключа асимметричной криптографии.
Заголовок JWT содержит информацию о типе токена и алгоритме подписи:
{
"alg": "HS256",
"typ": "JWT"
}
Поле alg определяет, каким способом формируется и
проверяется подпись. На практике используются:
Подпись защищает токен от подделки. При проверке сервер пересчитывает подпись и сравнивает её с полученной.
alg: noneИсторически в спецификации JWT существовал режим, при котором подпись отсутствует:
{
"alg": "none"
}
В этом случае токен считается «неподписанным», а поле подписи либо пустое, либо игнорируется.
Критическая проблема возникает тогда, когда сервер или библиотека:
alg, пришедшему из токенаnone как валидный вариантЭто приводит к ситуации, когда злоумышленник может:
alg: noneБиблиотека jsrsasign предоставляет функциональность для работы с JWT
через объект KJUR.jws.JWS.
Пример генерации токена:
const header = { alg: "HS256", typ: "JWT" };
const payload = { user: "alice", role: "user" };
const secret = "secret-key";
const token = KJUR.jws.JWS.sign("HS256", header, payload, secret);
Проверка:
const isValid = KJUR.jws.JWS.verifyJWT(token, "secret-key", {
alg: ["HS256"]
});
Проблема возникает, если:
algnoneЗлоумышленник может сформировать JWT вручную:
const header = {
alg: "none",
typ: "JWT"
};
const payload = {
user: "admin",
role: "administrator"
};
Токен формируется без подписи:
base64(header).base64(payload).
Если проверяющая сторона использует некорректную логику:
KJUR.jws.JWS.verifyJWT(token, null);
или не ограничивает алгоритмы, возможна ситуация, когда:
none принимается как допустимыйНаиболее опасные паттерны:
1. Отсутствие whitelist алгоритмов
KJUR.jws.JWS.verifyJWT(token, key, {});
В этом случае библиотека может принять alg из заголовка
без ограничений.
2. Доверие полю header.alg
Если система делает выбор алгоритма на основе входного токена:
const alg = decodedHeader.alg;
это создаёт возможность подмены механизма проверки.
3. Игнорирование подписи при none
Некоторые реализации исторически интерпретировали none
как «пропустить проверку».
Сценарий эксплуатации обычно включает:
Получение валидного JWT
Декодирование payload
Изменение критичных полей (роль, доступ)
Установка:
{ "alg": "none" }Удаление подписи
Отправка токена на сервер
Если сервер не проверяет алгоритм строго — токен принимается.
Правильная проверка должна включать жёсткое ограничение алгоритмов:
const isValid = KJUR.jws.JWS.verifyJWT(token, secret, {
alg: ["HS256"]
});
Ключевые принципы:
nonenone особенно
опасенАлгоритм none разрушает саму модель безопасности
JWT:
В сочетании с ошибками в библиотеке или конфигурации это превращается в прямой обход авторизации.
algКорректная модель всегда предполагает:
algconst options = {
alg: ["HS256"]
};
KJUR.jws.JWS.verifyJWT(token, secret, options);
Любое отклонение от этой модели создаёт поверхность атаки, в которой
alg: none становится наиболее простым способом обхода
защиты.