Защита заголовка: crit параметр

В спецификациях JOSE (JSON Object Signing and Encryption), на которых основаны JWS и JWE, заголовок токена играет критическую роль в процессе верификации подписи и интерпретации содержимого. Он содержит метаданные, влияющие на безопасность и корректность обработки токена. Одним из наиболее чувствительных элементов заголовка является параметр crit (critical), который определяет список обязательных расширенных параметров, требующих строгой обработки.

= { alg, typ, kid, crit, }

Параметр crit представляет собой массив строк, каждая из которых указывает на нестандартное или расширенное поле заголовка, которое обязательно должно быть распознано и обработано реализацией. Если библиотека или сервис не понимает хотя бы одно из указанных значений, токен должен быть отклонён.


Смысл критических параметров в безопасности JWT

Основная цель crit — предотвратить ситуацию, когда неизвестные или расширенные поля игнорируются, но при этом влияют на безопасность.

Если расширенный параметр влияет на:

  • алгоритм проверки подписи,
  • интерпретацию ключа,
  • условия валидности токена,

но библиотека его игнорирует, возникает риск обхода защиты.

Параметр crit заставляет реализацию явно подтвердить поддержку всех перечисленных расширений.


Структура заголовка с crit

Пример JWT заголовка:

{
  "alg": "HS256",
  "typ": "JWT",
  "kid": "key-123",
  "x5u": "https://example.com/cert.pem",
  "crit": ["x5u"]
}

Здесь:

  • x5u — нестандартный параметр (URL сертификата)
  • crit указывает, что x5u обязателен к обработке

Если библиотека не поддерживает x5u, токен должен быть отклонён.


Поведение jsrsasign при обработке crit

Библиотека Jsrsasign реализует работу с JWS/JWT в JavaScript и предоставляет инструменты для проверки подписи, декодирования и валидации заголовков.

При обработке crit важно учитывать:

  1. Jsrsasign не игнорирует неизвестные критические параметры по умолчанию
  2. Поведение зависит от используемых API (например, KJUR.jws.JWS.verify и KJUR.jws.JWS.parse)
  3. Проверка критических параметров должна выполняться вручную при расширенных сценариях

Ручная проверка критических параметров

Jsrsasign предоставляет базовый разбор JWT, но разработчик часто должен самостоятельно валидировать crit.

Пример:

const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImNyaXQiOlsieDV1Il0sIng1dSI6Imh0dHBzOi8vZXhhbXBsZS5jb20ifQ...";

const parsed = KJUR.jws.JWS.parse(token);

const header = parsed.headerObj;

// Проверка наличия crit
if (header.crit) {
    const supported = ["x5u"];

    for (let param of header.crit) {
        if (!supported.includes(param)) {
            throw new Error("Unsupported critical header parameter: " + param);
        }
    }
}

Ошибки игнорирования crit

Игнорирование критических параметров приводит к фундаментальным уязвимостям:

1. Обход проверки подписи

Если критический параметр влияет на выбор ключа (kid, jku, x5u), злоумышленник может подменить источник ключа.

2. Подмена криптографического контекста

Расширенные алгоритмы могут изменять способ формирования подписи.

3. Ошибочная валидация токена

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


Расширенные параметры и их взаимодействие с crit

На практике crit часто используется вместе с параметрами:

  • x5u — URL X.509 сертификата
  • x5t — thumbprint сертификата
  • jku — URL набора JWK ключей
  • кастомные поля (exp_delta, aud_req, nonce)

Пример сложного заголовка:

{
  "alg": "RS256",
  "typ": "JWT",
  "jku": "https://auth.example.com/keys",
  "kid": "rsa-key-1",
  "crit": ["jku"]
}

Если jku указан как критический, библиотека обязана получить и использовать ключи только из указанного источника.


Влияние на процесс проверки подписи

(JWT) = + + +

Параметр crit добавляет обязательный этап:

  1. Разбор заголовка
  2. Проверка списка критических параметров
  3. Подтверждение поддержки всех значений
  4. Только затем — выбор ключа и проверка подписи

Если этап 2 не пройден, дальнейшая обработка невозможна.


Jsrsasign и кастомные расширения JOSE

Jsrsasign позволяет работать с расширенными сценариями JWT, но не всегда автоматически интерпретирует нестандартные поля.

Поэтому при проектировании системы на Jsrsasign важно:

  • Явно документировать все кастомные заголовки
  • Поддерживать whitelist критических параметров
  • Не полагаться на автоматическое игнорирование неизвестных полей

Практический пример безопасной архитектуры

function verifyToken(token, key) {
    const parsed = KJUR.jws.JWS.parse(token);
    const header = parsed.headerObj;

    const allowedCrit = ["x5u", "jku"];

    if (header.crit) {
        for (const c of header.crit) {
            if (!allowedCrit.includes(c)) {
                throw new Error("Critical parameter not supported: " + c);
            }
        }
    }

    return KJUR.jws.JWS.verify(token, key);
}

Роль crit в стандартах JOSE

В спецификации RFC 7515 (JWS) параметр crit определён как механизм обязательной обработки расширений. Он не является опциональной метаинформацией, а представляет собой строгий контракт между эмитентом и валидатором токена.

Если хотя бы один участник цепочки не соблюдает правило обработки crit, вся модель доверия нарушается.


Типичные ошибки разработчиков

  • Полное игнорирование crit
  • Отсутствие whitelist поддержки
  • Использование сторонних JWT-библиотек без проверки расширений
  • Подмена доверенных источников ключей через jku без контроля crit

Поведение в реальных интеграциях

В системах авторизации на базе JWT:

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

Jsrsasign в таких архитектурах выступает как низкоуровневый криптографический слой, но ответственность за интерпретацию crit остаётся на разработчике.


Безопасная модель обработки заголовка

= + +

Любое отклонение от этой модели приводит к снижению криптографической гарантии системы, даже при корректной подписи токена.