JSON Web Token в контексте спецификации JWS (JSON Web Signature)
представляет собой структуру, состоящую из трех частей: заголовка
(header), полезной нагрузки (payload) и подписи (signature). Ключевым
элементом, определяющим безопасность токена, является алгоритм подписи,
указанный в заголовке через поле alg.
В библиотеке jsrsasign реализация JWT строится поверх криптографических примитивов, поддерживающих симметричные и асимметричные алгоритмы. От выбора алгоритма зависит не только уровень безопасности, но и архитектура системы: хранение ключей, распределение доверия, возможность проверки токенов на стороне клиента или сервера.
Заголовок JWT в jsrsasign обычно формируется как JSON-объект, где указывается тип токена и алгоритм подписи:
{
"alg": "HS256",
"typ": "JWT"
}
Поле alg определяет криптографическую схему:
В jsrsasign эти алгоритмы напрямую связаны с функциями JWS API.
HMAC (Hash-based Message Authentication Code) использует один общий секретный ключ для подписи и проверки токена. В jsrsasign это реализуется через алгоритмы SHA-2.
HMAC(K, m) = H((K opad) | H((K ipad) | m))
Где:
const header = { alg: "HS256", typ: "JWT" };
const payload = { sub: "1234567890", name: "Ivan", admin: true };
const sHeader = JSON.stringify(header);
const sPayload = JSON.stringify(payload);
const secret = "my-very-secret-key";
const token = KJUR.jws.JWS.sign(
"HS256",
sHeader,
sPayload,
secret
);
const isValid = KJUR.jws.JWS.verify(token, secret, ["HS256"]);
RSA использует пару ключей:
c = m^e n
и
m = c^d n
где:
const header = { alg: "RS256", typ: "JWT" };
const payload = { userId: "42" };
const privateKey = `-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----`;
const token = KJUR.jws.JWS.sign(
"RS256",
header,
payload,
privateKey
);
const publicKey = `-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----`;
const isValid = KJUR.jws.JWS.verify(token, publicKey, ["RS256"]);
RSA-PSS (Probabilistic Signature Scheme) добавляет случайность в процесс подписи, делая её устойчивой к определённым криптоаналитическим атакам.
В jsrsasign алгоритмы PS256 и аналоги работают поверх SHA-2 и MGF1.
const header = { alg: "PS256", typ: "JWT" };
const payload = { role: "admin" };
const token = KJUR.jws.JWS.sign(
"PS256",
header,
payload,
privateKey
);
const isValid = KJUR.jws.JWS.verify(token, publicKey, ["PS256"]);
ECC (Elliptic Curve Cryptography) основана на математике эллиптических кривых. Безопасность достигается сложностью задачи дискретного логарифма.
y^2 = x^3 + ax + b
const header = { alg: "ES256", typ: "JWT" };
const payload = { session: "abc123" };
const token = KJUR.jws.JWS.sign(
"ES256",
header,
payload,
privateKeyEC
);
const isValid = KJUR.jws.JWS.verify(token, publicKeyEC, ["ES256"]);
При создании JWT библиотека jsrsasign формирует JWS следующим образом:
Алгоритм выбирается явно:
KJUR.jws.JWS.sign(alg, header, payload, key)
При проверке возможно ограничение списка допустимых алгоритмов:
KJUR.jws.JWS.verify(token, key, ["HS256", "RS256"])
Это защищает от атак подмены алгоритма (algorithm confusion attack), когда злоумышленник пытается заменить RSA на HMAC.
Выбор алгоритма определяется архитектурой:
Ключевым принципом остаётся неизменность алгоритма на протяжении
всего жизненного цикла токена. Любая смена alg без контроля
приводит к нарушению совместимости и потенциальным уязвимостям.
В jsrsasign критически важно фиксировать список разрешённых алгоритмов при проверке:
KJUR.jws.JWS.verify(token, key, ["RS256"]);
Без этого возможно навязывание другого алгоритма, особенно если система поддерживает несколько схем одновременно.
Подпись JWT формируется над строкой:
base64url(header) + "." + base64url(payload)
И затем преобразуется в бинарную подпись согласно выбранному алгоритму. В зависимости от схемы используется SHA-2 семейство или ECDSA.
alg