Вопрос

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

Предположим, что у меня есть произвольный объект JSON, который может содержать любое количество данных, включая другие вложенные объекты JSON. Что я хочу, так это криптографический хэш/дайджест данных JSON, без учета фактического форматирования JSON (EG: игнорирование новейсов и различий между токенами JSON).

Последняя часть является требованием, поскольку JSON будет генерироваться/прочитать различными (DE) сериализаторами на ряде различных платформ. Я знаю по крайней мере одну библиотеку JSON для Java, которая полностью удаляет форматирование при чтении данных во время десериализации. Таким образом, это сломает хэш.

Приведенная выше пункт о данных также усложняет ситуацию, поскольку это мешает мне принимать известные поля в данном порядке и объединять их до хэсинга (подумайте примерно, как работает метод некриптографического хэшкода Java).

Наконец, хэширование всей строки JSON в виде куски байтов (до опустошения) также не желательна, поскольку в JSON есть поля, которые следует игнорировать при вычислении хэша.

Я не уверен, что есть хорошее решение этой проблемы, но я приветствую любые подходы или мысли =)

Это было полезно?

Решение

Проблема является распространенной при вычислении хэшей для любого формата данных, где допускается гибкость. Чтобы решить это, вам нужно канониказировать представление.

Например, протокол OAuth1.0a, который используется Twitter и другими службами для аутентификации, требует безопасного хэша сообщения запроса. Чтобы вычислить хэш, OAuth1.0a говорит, что вам нужно сначала алфавит поля, разделить их на новички, удалить имена поля (которые хорошо известны) и использовать пустые линии для пустых значений. Подпись или хэш рассчитывается в результате этой канонизации.

XML DSIG работает так же - вам нужно канонизировать XML перед его подписанием. Eсть предложенный стандарт W3, охватывающий это, потому что это такое фундаментальное требование для подписания. Некоторые люди называют это c14n.

Я не знаю стандарта канонизации для JSON. Это стоит исследовать.

Если его нет, вы, конечно, можете установить соглашение для вашего конкретного использования приложения. Разумным началом может быть:

  • лексикографически сортировать свойства по имени
  • Двойные цитаты, используемые на всех именах
  • Двойные кавычки, используемые на всех строковых значениях
  • Нет места или одного пространства, между именами и толстой кишкой, а также между толстой кишкой и значением
  • Нет пробелов между значениями и следующей запятой
  • Все остальное белое пространство обрушилось на одно пространство или ничего - выберите его
  • Исключите любые свойства, которые вы не хотите подписывать (один из примеров, свойство, которое удерживает саму подпись)
  • подписать результат, с выбранным вами алгоритмом

Вы также можете захотеть подумать о том, как пройти эту подпись в объекте JSON-возможно, установить известное имя свойства, например «Nichols-Hmac» или что-то в этом роде, что получает кодируемую версию Base64 хэша. Это свойство должно быть явно исключено из -за алгоритма хеширования. Затем любой приемник JSON сможет проверить хэш.

Каноницированное представление не должно быть представлением, которое вы передаете в приложении. Его нужно легко создать, учитывая произвольный объект JSON.

Другие советы

Вместо изобретения собственной нормализации/канонизации JSON вы можете использовать Bencode. Анкет Семантически это то же самое, что и JSON (состав чисел, строк, списков и дик), но с свойством однозначного кодирования, которое необходимо для криптографического хэширования.

Bencode используется в качестве формата торрент -файла, каждый клиент BitTorrent содержит реализацию.

Это та же проблема, что и вызывает проблемы с подписями S/MIME и подписями XML. То есть существует несколько эквивалентных представлений данных, которые будут подписаны.

Например, в JSON:

{  "Name1": "Value1", "Name2": "Value2" }

против.

{
    "Name1": "Value\u0031",
    "Name2": "Value\u0032"
}

Или в зависимости от вашего приложения, это может быть даже эквивалентно:

{
    "Name1": "Value\u0031",
    "Name2": "Value\u0032",
    "Optional": null
}

Каноникализация может решить эту проблему, но это проблема, которая вам вообще не нужна.

Легкое решение, если у вас есть контроль над спецификацией, состоит в том, чтобы обернуть объект в какой -то контейнер, чтобы защитить его от преобразования в «эквивалентное», но другое представление.

Т.е. избегайте проблемы, не подписав «логический» объект, а подписав конкретное сериализованное представление этого.

Например, JSON Objects -> UTF -8 Text -> Bytes. Подписать байты как байты, затем передайте их как байты Например, кодирование BASE64. Поскольку вы подписываете байты, различия, такие как пробелы, являются частью того, что подписано.

Вместо того, чтобы пытаться сделать это:

{  
   "JSONContent": {  "Name1": "Value1", "Name2": "Value2" },
   "Signature": "asdflkajsdrliuejadceaageaetge="
}

Просто сделай это:

{
   "Base64JSONContent": "eyAgIk5hbWUxIjogIlZhbHVlMSIsICJOYW1lMiI6ICJWYWx1ZTIiIH0s",
   "Signature": "asdflkajsdrliuejadceaageaetge="

}

Т.е. не подписывайте JSON, подпишите байты закодированных Json.

Да, это означает, что подпись больше не прозрачна.

JSON-LD может сделать нормальное изображение.

Вам придется определить свой контекст.

RFC 7638: Отпечаток большого пальца JSON (JWK) включает тип канонизации. Хотя RFC7638 ожидает ограниченный набор участников, мы сможем применить тот же расчет для любого члена.

https://tools.ietf.org/html/rfc7638#section-3

Я бы сделал все поля в данном порядке (например, в алфавитном порядке). Почему произвольные данные имеют значение? Вы можете просто итерации над свойствами (отражение ALA).

В качестве альтернативы, я бы изучил преобразование необработанной строки JSON в некоторую четко определенную каноническую форму (удалите все излишнее форматирование) - и хитровая.

Мы столкнулись с простой проблемой с хэшинг, кодируемыми JSON, полезными нагрузками. В нашем случае мы используем следующую методологию:

  1. Преобразовать данные в объект JSON;
  2. Кодировать полезную нагрузку JSON в BASE64
  3. Сообщение DIGEST (HMAC) Полезная полезная нагрузка BASE64.
  4. Передача базы64 полезная нагрузка.

Преимущества использования этого решения:

  1. Base64 будет производить тот же выход для данной полезной нагрузки.
  2. Поскольку полученная подпись будет получена непосредственно из полезной нагрузки Base64, и, поскольку между конечными точками будет обменена нагрузка Base64 Pay-платы, мы будем уверены, что подпись и полезная нагрузка будут сохранены.
  3. Это решение решает проблемы, возникающие из -за различия в кодировании специальных символов.

Недостатки

  1. Кодирование/декодирование полезной нагрузки может добавить накладные расходы
  2. Base64-кодируемые данные обычно на 30% больше, чем исходная полезная нагрузка.
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top