Алгоритмы подписи JWT в jsrsasign

Основы JWS и роль алгоритма подписи

JSON Web Token в контексте спецификации JWS (JSON Web Signature) представляет собой структуру, состоящую из трех частей: заголовка (header), полезной нагрузки (payload) и подписи (signature). Ключевым элементом, определяющим безопасность токена, является алгоритм подписи, указанный в заголовке через поле alg.

В библиотеке jsrsasign реализация JWT строится поверх криптографических примитивов, поддерживающих симметричные и асимметричные алгоритмы. От выбора алгоритма зависит не только уровень безопасности, но и архитектура системы: хранение ключей, распределение доверия, возможность проверки токенов на стороне клиента или сервера.

Структура заголовка JWT и поле alg

Заголовок JWT в jsrsasign обычно формируется как JSON-объект, где указывается тип токена и алгоритм подписи:

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

Поле alg определяет криптографическую схему:

  • симметричные алгоритмы (HMAC): HS256, HS384, HS512
  • асимметричные алгоритмы (RSA): RS256, RS384, RS512
  • схемы RSA-PSS: PS256, PS384, PS512
  • эллиптические кривые: ES256, ES384, ES512

В jsrsasign эти алгоритмы напрямую связаны с функциями JWS API.


Симметричные алгоритмы HMAC (HS256, HS384, HS512)

Принцип работы HMAC

HMAC (Hash-based Message Authentication Code) использует один общий секретный ключ для подписи и проверки токена. В jsrsasign это реализуется через алгоритмы SHA-2.

HMAC(K, m) = H((K opad) | H((K ipad) | m))

Где:

  • K — секретный ключ
  • m — сообщение (header + payload)
  • H — хеш-функция (SHA-256, SHA-384, SHA-512)

Реализация HS256 в jsrsasign

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"]);

Особенности HS256

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

RSA-алгоритмы (RS256, RS384, RS512)

Принцип асимметричной криптографии

RSA использует пару ключей:

  • private key — используется для подписи
  • public key — используется для проверки

c = m^e n

и

m = c^d n

где:

  • e — публичная экспонента
  • d — приватная экспонента
  • n — модуль RSA

Подпись RS256 в jsrsasign

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
);

Проверка RS256

const publicKey = `-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----`;

const isValid = KJUR.jws.JWS.verify(token, publicKey, ["RS256"]);

Особенности RSA-алгоритмов

  • высокая безопасность при корректной длине ключа (2048+ бит)
  • медленнее HMAC
  • широко используется в OAuth2 и OpenID Connect
  • удобен для публичной проверки токенов

RSA-PSS (PS256, PS384, PS512)

Отличие от классического RSA

RSA-PSS (Probabilistic Signature Scheme) добавляет случайность в процесс подписи, делая её устойчивой к определённым криптоаналитическим атакам.

В jsrsasign алгоритмы PS256 и аналоги работают поверх SHA-2 и MGF1.

Пример подписи PS256

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"]);

Особенности RSA-PSS

  • более современный стандарт по сравнению с RS256
  • повышенная криптостойкость
  • требует поддержки в обеих сторонах (подпись/проверка)

Алгоритмы на эллиптических кривых (ES256, ES384, ES512)

Принцип ECC

ECC (Elliptic Curve Cryptography) основана на математике эллиптических кривых. Безопасность достигается сложностью задачи дискретного логарифма.

y^2 = x^3 + ax + b

Преимущества ECC

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

ES256 в jsrsasign

const header = { alg: "ES256", typ: "JWT" };
const payload = { session: "abc123" };

const token = KJUR.jws.JWS.sign(
  "ES256",
  header,
  payload,
  privateKeyEC
);

Проверка ES256

const isValid = KJUR.jws.JWS.verify(token, publicKeyEC, ["ES256"]);

Особенности ES256

  • ключи короче RSA при сопоставимой безопасности
  • сложнее в реализации и отладке
  • чувствительность к формату ключей (PEM/DER)

Обработка алгоритма alg в jsrsasign

При создании JWT библиотека jsrsasign формирует JWS следующим образом:

  1. сериализация header и payload
  2. base64url encoding
  3. вычисление подписи согласно alg
  4. формирование итогового токена

Алгоритм выбирается явно:

KJUR.jws.JWS.sign(alg, header, payload, key)

При проверке возможно ограничение списка допустимых алгоритмов:

KJUR.jws.JWS.verify(token, key, ["HS256", "RS256"])

Это защищает от атак подмены алгоритма (algorithm confusion attack), когда злоумышленник пытается заменить RSA на HMAC.


Сравнение алгоритмов подписи JWT

HMAC (HS256)

  • один ключ
  • быстро
  • требует строгого контроля секрета

RSA (RS256)

  • разделение ключей
  • удобен для публичной верификации
  • медленнее HMAC

RSA-PSS (PS256)

  • современный стандарт RSA
  • повышенная стойкость
  • требует более новых библиотек

ECC (ES256)

  • компактные ключи
  • высокая производительность
  • сложнее в реализации

Практика выбора алгоритма в jsrsasign

Выбор алгоритма определяется архитектурой:

  • монолитные приложения → HS256
  • микросервисы и публичные API → RS256 / PS256
  • мобильные и высоконагруженные системы → ES256

Ключевым принципом остаётся неизменность алгоритма на протяжении всего жизненного цикла токена. Любая смена alg без контроля приводит к нарушению совместимости и потенциальным уязвимостям.


Типовые ошибки при работе с alg

  • использование HS256 с публично доступным секретом
  • отсутствие ограничения допустимых алгоритмов при verify
  • смешивание RSA и HMAC в одной системе без строгой валидации
  • хранение приватных ключей RSA в клиентском коде
  • игнорирование различий между ES256 и RS256 при миграции

Механизм защиты от подмены алгоритма

В jsrsasign критически важно фиксировать список разрешённых алгоритмов при проверке:

KJUR.jws.JWS.verify(token, key, ["RS256"]);

Без этого возможно навязывание другого алгоритма, особенно если система поддерживает несколько схем одновременно.


Внутреннее представление подписи

Подпись JWT формируется над строкой:

base64url(header) + "." + base64url(payload)

И затем преобразуется в бинарную подпись согласно выбранному алгоритму. В зависимости от схемы используется SHA-2 семейство или ECDSA.


Итоговая логика выбора в jsrsasign

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