Когда бы вы использовали незащищенный заголовок JWS?
Я не понимаю, почему существуют незащищенные заголовки JWS.
В некоторых случаях: незащищенный заголовок JWS содержит параметры, которые не защищены целостностью и могут использоваться только для подписи с сериализацией JSON.
Если бы они могли использоваться в качестве заголовка верхнего уровня, я мог понять, почему кто-то может захотеть включить изменяемый параметр (который не изменит подпись). Однако, это не так.
Кто-нибудь может придумать варианты использования или знать, почему они включены в спецификацию?
Спасибо!
2 ответа
Ответ Флорента оставляет меня неудовлетворенным.
Что касается примера использования JWT для подписи хеша документа... утверждение состоит в том, что алгоритм и keyID будут "конфиденциальными данными", которые должны быть "защищены". Я предполагаю, что он имеет в виду "подписанный". Но нет необходимости подписывать алгоритм и keyID.
пример
Предположим, что Боб создает подписанный JWT, который содержит незащищенный заголовок, утверждая alg=HS256 и keyid=XXXX1 . Этот JWT предназначен для передачи Алисе.
Случай 1
Предположим, Мэллори перехватывает подписанный JWT, отправленный Бобом. Затем Мэллори создает новый незащищенный заголовок, утверждая alg=None.
Получатель (Алиса) теперь отвечает за проверку подписи на полезной нагрузке. Алиса не должна быть удовлетворена "без подписи"; На самом деле Алиса не должна полагаться на утверждение клиента (отправителя), чтобы определить, какой алгоритм подписи для нее приемлем. Поэтому Алиса отклоняет JWT с надуманным заголовком "без подписи".
Дело 2
Предположим, что Мэллори создает заголовок с alg=RS256 и keyId=XXX1. Теперь Алиса пытается проверить подпись и находит:
- алгоритм не соответствует
- ключ, указанный для этого алгоритма, не существует
Поэтому Алиса отвергает JWT.
Дело 3
Предположим, Мэллори создает заголовок с alg=HS256 и keyId=ZZ3. Теперь Алиса пытается проверить подпись и обнаруживает, что ключ неизвестен, и отклоняет JWT.
Ни в коем случае алгоритм не должен быть частью подписанного материала. Не существует сценария, при котором незащищенный заголовок приводит к уязвимости или нарушению целостности.
Возвращаясь к первоначальному вопросу
Первоначальный вопрос был: какова цель незащищенного заголовка JWT?
Вкратце, цель незащищенного заголовка JWS состоит в том, чтобы позволить транспортировку некоторых метаданных, которые могут использоваться в качестве подсказок для получателя. Как и alg (алгоритм) и kid (идентификатор ключа). Флоран предполагает, что вставка данных в незащищенный заголовок может привести к эффективности. Это не веская причина. Вот ключевой момент: утверждения в незащищенном заголовке являются подсказками, на которые нельзя полагаться или которым можно доверять.
Более интересный вопрос: какова цель защищенного заголовка JWS? Зачем иметь положение, которое подписывает как "заголовок", так и "полезную нагрузку"? В случае Защищенного заголовка JWS заголовок и полезная нагрузка объединяются, и результат подписывается. Предполагая, что заголовок -JSON, а полезная нагрузка -JSON, на данный момент нет семантического различия между заголовком и полезной нагрузкой. Так зачем вообще ставить подпись под заголовком?
Можно просто положиться на JWS с незащищенными заголовками. Если есть необходимость в заявлениях с защитой целостности, поместите их в полезную нагрузку. Если нужны подсказки, поместите их в незащищенный заголовок. Подпишите полезную нагрузку, а не заголовок. Просто.
Это работает и действует. Но это предполагает, что полезной нагрузкой является JSON. Это верно для JWT, но не верно для всех JWS. RFC 7515, который определяет JWS, не требует, чтобы подписанная полезная нагрузка была JSON. Представьте, что полезная нагрузка представляет собой цифровое изображение медицинского сканирования. Это не JSON. К этому нельзя просто "приложить претензии". Поэтому JWS допускает защищенный заголовок, так что (не JSON) полезная нагрузка И произвольные утверждения могут быть подписаны и проверена целостность.
В случае, когда полезная нагрузка не является JSON, а заголовок защищен, нет возможности включить "дополнительные не подписанные заголовки" в JWS. Если существует необходимость отправки некоторых данных, которые должны быть проверены на целостность, а других, которые просто являются "подсказками", то на самом деле существует только один контейнер: защищенный заголовок. И намеки подписываются вместе с реальными претензиями.
Можно было бы избежать необходимости этого трюка с защищенным заголовком, просто обернув JSON-хеш вокруг данных, которые нужно подписать. Например:
{
"image" : "qw93u9839839...base64-encoded image data..."
}
И после этого можно добавить претензии к этой оболочке JSON.
{
"image" : "qw93u9839839...base64-encoded image data..."
"author" : "Whatever"
}
И тогда эти требования будут подписаны и проверены на честность.
Но в случае двоичных данных кодирование их в строку, позволяющее инкапсуляцию в JSON, может значительно увеличить данные. JWS с полезной нагрузкой не-JSON избегает этого.
НТН
RFC дает нам примеры незащищенных заголовков следующим образом:
А.6.2. Незащищенные заголовки JWS для каждой подписи
Значения идентификатора ключа предоставляются для обоих ключей с использованием параметров заголовка подписи. Два значения незащищенного заголовка JWS, используемые для представления этих идентификаторов ключей:
{"kid":"2010-12-29"}
и
{"kid":"e9bc097a-ce51-4036-9562-d2ade882db0d"}
https://datatracker.ietf.org/doc/html/rfc7515#appendix-A.6.2
Использование в примере, скорее всего, не случайно. Поскольку JWS допускает использование нескольких подписей для одной полезной нагрузки, система подсказок в открытом виде может оказаться полезной. Например, если ключ недоступен верификатору (серверу), то декодирование защищенного заголовка можно пропустить. Термин «подсказка» фактически используется в определении:
4.1.4. "ребенок" (идентификатор ключа) Параметр заголовка
Параметр заголовка «ребенок» (идентификатор ключа) — это подсказка, указывающая, какой ключ использовался для защиты JWS. Этот параметр позволяет отправителям явно сигнализировать об изменении ключа получателям. Структура значения «ребенок» не определена. Его значение ДОЛЖНО быть строкой с учетом регистра. Использование этого параметра заголовка НЕОБЯЗАТЕЛЬНО.
https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.4
Если мы посмотрим на идентификацию ключа, в нем упоминается, где вы не должны быть защищены целостностью (то есть: часть незащищенных заголовков): (выделено мной)
6. Идентификация ключа
Получатель JWS должен иметь возможность определить ключ, который использовался для цифровой подписи или операции MAC. Используемый ключ может быть идентифицирован с использованием методов параметров заголовка, описанных в разделе 4.1, или может быть идентифицирован с использованием методов, которые выходят за рамки данной спецификации. В частности, параметры заголовка «jku», «jwk», «kid», «x5u», «x5c», «x5t» и «x5t#S256» могут использоваться для идентификации используемого ключа. Эти параметры заголовка ДОЛЖНЫ быть защищены целостностью, если информация, которую они передают, должна использоваться в решении о доверии; однако, если единственной информацией, используемой в решении о доверии, является ключ, эти параметры не нуждаются в защите целостности,
Производитель ДОЛЖЕН включать в параметры заголовка достаточную информацию для идентификации используемого ключа, если приложение не использует другие средства или соглашение для определения используемого ключа. Проверка подписи или MAC завершается ошибкой, когда для используемого алгоритма требуется ключ (что верно для всех алгоритмов, кроме «none»), а используемый ключ не может быть определен.
Средства обмена любыми используемыми общими симметричными ключами выходят за рамки этой спецификации.
https://datatracker.ietf.org/doc/html/rfc7515#section-6
Упрощенно, если у вас есть сообщение о том, что кто-то модифицирует ключ, он будет ссылаться на другой ключ, тогда сама подпись не будет совпадать. Поэтому вам не нужно включать в защищенный заголовок. Хорошим примером первой части, где информация, которую они передают, должна использоваться для принятия решения о доверии, является ACME (также известный как протокол Let's Encrypt). При создании учетной записи и хранении ключевых данных вы хотите доверять домену . Мы хотим сохранить , поэтому нам нужно убедиться, что он действителен. После того, как сервер сохранил и может использовать его для получения ключа, мы можем отправлять сообщения и ссылаться на незащищенный заголовок (это не делается ACME, но возможно). Так как мы собираемся только проверить подпись, то используется подсказка или ссылка на которую была использована учетная запись. Если это поле изменено, то оно Я укажу на несуществующий или совсем другой ключ и не пройду проверку подписи. Это означает, что само по себе является «единственной информацией, используемой в решении о доверии».
Есть также более теоретические сценарии, которые, зная, как это работает, вы можете придумать.
Например: идея иметь несколько подписей, которые вы можете передать (обменять). Право подписи может включать одну подпись для посредника (сервера) и другую для другого получателя (конечного пользователя-клиента). Это отличается тем, что серверу не нужно проверять или даже декодировать защищенный заголовок или подпись. Или, возможно, у посредника нет секрета клиента, чтобы проверить подпись.
Например, сообщение с несколькими получателями (например, чат) может быть обработано ретранслятором/прокси-сервером и, используя незащищенный заголовок, передать реконструированный компактный JWS (${protected}.${payload}.${signature}
) для каждого получателя на основе (или любого другого настраиваемого незащищенного поля заголовка, напримерuserId
илиendpoint
).
Другим примером может быть сервер с доступом ко многим различным ключам и открытому тексту.kid
будет быстрее, чем повторять и декодировать каждое защищенное поле, чтобы найти, какое именно.
С одной стороны, все, что вы делаете, это пропускаете декодирование base64url защищенного заголовка для повышения производительности, но если вы собираетесь проксировать/ретранслировать данные, то вы не загрязняете защищенный заголовок, предназначенный для другого получателя.