Модуль jwt

Модуль JWT в библиотеке jsrsasign предназначен для создания, подписи, верификации и декодирования JSON Web Token. Внутри он опирается на криптографические примитивы (RSA, ECDSA, HMAC) и стандарты JOSE (JSON Object Signing and Encryption).

JWT состоит из трёх частей:

  • Header — метаданные токена (алгоритм, тип)
  • Payload — полезная нагрузка (claims)
  • Signature — криптографическая подпись

Формат:

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

В jsrsasign работа с JWT сосредоточена в пространстве имён KJUR.jws.


Создание JWT (подпись)

Основной метод:

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

Параметры:

  • alg — алгоритм подписи (например, HS256, RS256, ES256)
  • header — JSON-строка заголовка
  • payload — JSON-строка данных
  • key — секрет (для HMAC) или приватный ключ (для RSA/ECDSA)
  • pass — пароль ключа (если используется защищённый PEM)

Пример HMAC (HS256):

const header = JSON.stringify({ alg: "HS256", typ: "JWT" });
const payload = JSON.stringify({ sub: "user123", iat: 1710000000 });

const token = KJUR.jws.JWS.sign("HS256", header, payload, "secret");

Пример RSA (RS256):

const privateKey = `-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----`;

const token = KJUR.jws.JWS.sign(
  "RS256",
  JSON.stringify({ alg: "RS256", typ: "JWT" }),
  JSON.stringify({ iss: "issuer", exp: 1710003600 }),
  privateKey
);

Верификация JWT

Метод:

KJUR.jws.JWS.verify(token, key, acceptAlgs)

Параметры:

  • token — строка JWT
  • key — секрет или публичный ключ
  • acceptAlgs — массив допустимых алгоритмов

Пример:

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

Важно:

  • Алгоритм токена должен входить в acceptAlgs
  • При HMAC используется тот же секрет
  • При RSA/ECDSA — публичный ключ

Декодирование JWT без проверки подписи

Метод:

KJUR.jws.JWS.parse(token)

Возвращает объект:

{
  headerObj: {...},
  payloadObj: {...},
  sigHex: "...",
  headerPP: "...",
  payloadPP: "..."
}

Пример:

const parsed = KJUR.jws.JWS.parse(token);
console.log(parsed.payloadObj.sub);

Используется только для чтения, без доверия данным.


Проверка с использованием JWT класса

Более высокоуровневый API:

KJUR.jws.JWT.verifyJWT(token, key, options)

options может включать:

  • alg — допустимые алгоритмы
  • iss — ожидаемый issuer
  • sub — subject
  • aud — аудитория
  • exp — проверка срока действия
  • nbf — not before

Пример:

const isValid = KJUR.jws.JWT.verifyJWT(token, publicKey, {
  alg: ["RS256"],
  iss: ["issuer"],
  verifyAt: KJUR.jws.IntDate.get("now")
});

Работа с временными claims

JWT часто содержит:

  • iat — время выпуска
  • exp — срок действия
  • nbf — не раньше чем

jsrsasign предоставляет утилиту:

KJUR.jws.IntDate.get("now")

Или:

KJUR.jws.IntDate.get("now + 1hour")

Пример генерации payload:

const payload = {
  sub: "user",
  iat: KJUR.jws.IntDate.get("now"),
  exp: KJUR.jws.IntDate.get("now + 1hour")
};

Поддерживаемые алгоритмы

HMAC:

  • HS256
  • HS384
  • HS512

RSA:

  • RS256
  • RS384
  • RS512

ECDSA:

  • ES256
  • ES384
  • ES512

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

  • формат ключа
  • длину подписи
  • производительность

Работа с ключами

HMAC

Простой строковый секрет:

const key = "my-secret";

RSA

Приватный ключ (подпись):

-----BEGIN PRIVATE KEY-----

Публичный ключ (проверка):

-----BEGIN PUBLIC KEY-----

ECDSA

Аналогично RSA, но ключи в формате EC.


Проверка структуры токена

Перед верификацией полезно убедиться, что токен корректен:

KJUR.jws.JWS.parse(token);

Ошибки:

  • неверный формат (не 3 части)
  • некорректный base64url
  • повреждённый JSON

Base64URL кодирование

JWT использует base64url вместо стандартного base64:

  • +-
  • /_
  • без =

jsrsasign автоматически обрабатывает это внутри.


Проверка алгоритма (важный аспект безопасности)

Нельзя доверять значению alg из заголовка без проверки:

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

Запрещено:

verify(token, key, null)

Иначе возможна атака подмены алгоритма.


Использование JSON вместо строк

jsrsasign требует строки JSON, но удобно использовать объекты:

const headerObj = { alg: "HS256", typ: "JWT" };
const payloadObj = { user: "admin" };

const token = KJUR.jws.JWS.sign(
  "HS256",
  JSON.stringify(headerObj),
  JSON.stringify(payloadObj),
  "secret"
);

Ошибки и исключения

Частые ошибки:

  • unsupported algorithm
  • key mismatch
  • invalid signature
  • malformed token

Обработка:

try {
  const valid = KJUR.jws.JWS.verify(token, key, ["HS256"]);
} catch (e) {
  console.error(e);
}

Генерация JWT с кастомными claims

Пример расширенного payload:

const payload = {
  iss: "auth-server",
  sub: "user123",
  aud: "client-app",
  role: "admin",
  permissions: ["read", "write"],
  iat: KJUR.jws.IntDate.get("now"),
  exp: KJUR.jws.IntDate.get("now + 2hour")
};

Работа с вложенными объектами

JWT допускает сложные структуры:

const payload = {
  user: {
    id: 1,
    name: "Alice"
  },
  meta: {
    ip: "127.0.0.1"
  }
};

Проверка audience (aud)

KJUR.jws.JWT.verifyJWT(token, key, {
  aud: ["my-app"]
});

Если aud не совпадает — токен считается недействительным.


Использование passphrase для ключей

Если ключ зашифрован:

KJUR.jws.JWS.sign("RS256", header, payload, privateKey, "password");

Производительность

  • HS256 быстрее, так как не использует асимметричную криптографию
  • RS256 медленнее, но безопаснее для распределённых систем
  • ES256 компактнее по размеру подписи

Частые сценарии применения

  • аутентификация (access tokens)
  • авторизация (claims с ролями)
  • обмен данными между сервисами
  • stateless-сессии

Ограничения

  • нет встроенного шифрования (JWE — отдельный модуль)
  • вся безопасность зависит от ключей
  • payload не защищён от чтения (только от изменения)

Практические рекомендации

  • всегда проверять алгоритм
  • использовать exp и nbf
  • минимизировать payload
  • не хранить чувствительные данные
  • использовать асимметричные алгоритмы для API

Внутренняя архитектура

Модуль JWT в jsrsasign построен поверх:

  • KJUR.crypto — криптография
  • KJUR.jws.JWS — подписи
  • KJUR.jws.JWT — логика проверки claims

Разделение позволяет гибко использовать как низкоуровневые, так и высокоуровневые API.


Расширенные возможности

  • поддержка нестандартных claims
  • интеграция с PEM, DER, HEX ключами
  • работа в браузере и Node.js
  • совместимость со стандартами RFC 7519, 7515

Пример полного цикла

// 1. Создание
const token = KJUR.jws.JWS.sign(
  "HS256",
  JSON.stringify({ alg: "HS256", typ: "JWT" }),
  JSON.stringify({ sub: "user", iat: KJUR.jws.IntDate.get("now") }),
  "secret"
);

// 2. Проверка
const valid = KJUR.jws.JWS.verify(token, "secret", ["HS256"]);

// 3. Чтение
const parsed = KJUR.jws.JWS.parse(token);

Такой цикл охватывает основные операции работы с JWT в jsrsasign.