Как надежно хешировать объекты JavaScript? - PullRequest
19 голосов
/ 06 апреля 2011

Есть ли надежный способ JSON.stringify JavaScript-объекта, который гарантирует, что конечная строка JSON одинакова во всех браузерах, node.js и т. Д., Учитывая, что объект Javascript одинаков?

Я хочу хэшировать объекты JS, такие как

{
  signed_data: object_to_sign,
  signature:   md5(JSON.stringify(object_to_sign) + secret_code)
}

и передавать их через веб-приложения (например, Python и node.js) и пользователю, чтобы пользователь мог проходить аутентификацию на одном сервисе и показывать следующий сервис "«подписанные данные», чтобы проверить подлинность этих данных.

Однако я столкнулся с проблемой, заключающейся в том, что JSON.stringify не является уникальным для всех реализаций:

  • В узле.js / V8, JSON.stringify возвращает строку JSON без лишних пробелов, например '{"user_id": 3}.
  • Python's simplejson.dumps оставляет некоторые пробелы, например' {"user_id": 3}'
  • Вероятно, другие реализации stringify могут по-разному работать с пробелами, порядком атрибутов или чем-либо еще.

Существует ли надежная перекрестная проверка?метод latform stringify?Есть ли «номинированный JSON»?

Вы бы порекомендовали другие способы хеширования подобных объектов?

ОБНОВЛЕНИЕ:

Это то, что я используюв качестве обходного пути:

normalised_json_data = JSON.stringify(object_to_sign)
{
  signed_data: normalised_json_data,
  signature:   md5(normalised_json_data + secret_code)
}

Таким образом, в этом подходе подписывается не сам объект, а его JSON-представление (специфичное для платформы sigining).Это хорошо работает, потому что я подписываю теперь однозначную строку, и я могу легко JSON.parse данные после того, как проверил хэш подписи.

Недостаток здесь в том, что если я отправлю всю {signature_data, signature}Я также должен вызывать JSON.parse дважды, и это выглядит не так хорошо, потому что внутренняя часть экранирована:

{"signature": "1c3763890298f5711c8b2ea4eb4c8833", "signed_data": "{\"user_id\":5}"}

Ответы [ 5 ]

32 голосов
/ 20 марта 2017

Вас может заинтересовать пакет npm object-hash , который, по-видимому, имеет довольно хороший уровень активности и надежности.

var hash = require('object-hash');

var testobj1 = {a: 1, b: 2};
var testobj2 = {b: 2, a: 1};
var testobj3 = {b: 2, a: "1"};

console.log(hash(testobj1)); // 214e9967a58b9eb94f4348d001233ab1b8b67a17
console.log(hash(testobj2)); // 214e9967a58b9eb94f4348d001233ab1b8b67a17
console.log(hash(testobj3)); // 4a575d3a96675c37ddcebabd8a1fea40bc19e862
7 голосов
/ 16 июня 2015

Это старый вопрос, но я подумал, что добавлю текущее решение этого вопроса для всех судей Google.

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

5 голосов
/ 06 апреля 2011

Вы просите, чтобы реализация на нескольких языках была одинаковой ... вам почти наверняка не повезло. У вас есть два варианта:

  • проверьте реализации www.json.org, чтобы увидеть, могут ли они быть более стандартизированы
  • сверните свое собственное на каждом языке (используйте реализации json.org как основу, и ОЧЕНЬ мало работы)
5 голосов
/ 06 апреля 2011

Вы можете нормализовать результат stringify(), применяя такие правила, как:

  • удаление ненужных пробелов
  • сортировка имен атрибутов в хешах
  • четко определенныесогласованный стиль цитирования
  • нормализует содержимое строки (поэтому "\ u0041" и "A" становятся одинаковыми)

Это оставит вас с каноническим представлением JSON вашего объекта, которое вытогда можно надежно хешировать.

1 голос
/ 27 февраля 2019

Попробовав некоторые алгоритмы хеширования и методы JSON-to-string, я обнаружил, что это работает лучше всего (извините, это машинопись, конечно, можно переписать в javascript):

// From: https://stackoverflow.com/questions/5467129/sort-javascript-object-by-key
function sortObjectKeys(obj){
    if(obj == null || obj == undefined){
        return obj;
    }
    if(typeof obj != 'object'){ // it is a primitive: number/string (in an array)
        return obj;
    }
    return Object.keys(obj).sort().reduce((acc,key)=>{
        if (Array.isArray(obj[key])){
            acc[key]=obj[key].map(sortObjectKeys);
        }
        else if (typeof obj[key] === 'object'){
            acc[key]=sortObjectKeys(obj[key]);
        }
        else{
            acc[key]=obj[key];
        }
        return acc;
    },{});
}
let xxhash64_ObjectToUniqueStringNoWhiteSpace = function(Obj : any)
{
    let SortedObject : any = sortObjectKeys(Obj);
    let jsonstring = JSON.stringify(SortedObject, function(k, v) { return v === undefined ? "undef" : v; });

    // Remove all whitespace
    let jsonstringNoWhitespace :string = jsonstring.replace(/\s+/g, '');

    let JSONBuffer: Buffer = Buffer.from(jsonstringNoWhitespace,'binary');   // encoding: encoding to use, optional.  Default is 'utf8'
    return xxhash.hash64(JSONBuffer, 0xCAFEBABE, "hex");
}

ИспользуетсяМодуль npm: https://cyan4973.github.io/xxHash/, https://www.npmjs.com/package/xxhash

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

  • Это детерминистический
  • Игнорирует порядок ключей (сохраняет порядок массивов)
  • Кроссплатформенность (если вы можете найти эквиваленты для JSON-stringify) Надеемся, что JSON-stringify не получит другой реализации, а удаление пробелов, мы надеемся, сделает его независимым от JSON-форматирования.
  • 64-bit
  • Шестнадцатеричная строка результат
  • Самый быстрый (0,021 мс для 2177 B JSON, 2,64 мс для 150 кБ JSON)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...