簡體   English   中英

如何可靠地 hash JavaScript 對象?

[英]How to reliably hash JavaScript objects?

Is there a reliable way to JSON.stringify a JavaScript object that guarantees that the ceated JSON string is the same across all browsers, Node.js and so on, given that the JavaScript object is the same?

我想 hash JavaScript 對象喜歡

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

並將它們傳遞給 web 應用程序(例如 Python 和 Node.js)和用戶,以便用戶可以針對一項服務進行身份驗證並顯示下一項服務“簽名數據”以檢查數據是否真實。

但是,我遇到的問題是JSON.stringify在實現中並不是真正獨一無二的:

  • 在 Node.js / V8 中, JSON.stringify返回一個沒有不必要空格的 JSON 字符串,例如 '{"user_id":3}。
  • Python 的simplejson.dumps會留下一些空格,例如'{"user_id": 3}'
  • 可能其他 stringify 實現可能會以不同的方式處理空格、屬性順序或其他任何內容。

有可靠的跨平台字符串化方法嗎? 是否有“規范化的 JSON”?

你會推薦其他方法來處理像這樣的 hash 對象嗎?

更新:

這是我用作解決方法的方法:

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

因此,在這種方法中,簽名的不是 object 本身,而是其 JSON 表示(特定於簽名平台)被簽名。 這很好用,因為我現在簽名的是一個明確的字符串,並且在我檢查了簽名 hash 之后,我可以輕松地JSON.parse數據。

這里的缺點是,如果我將整個{signed_data, signature} object 作為 JSON 發送,我必須調用JSON.parse兩次,因為它看起來不像 nice

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

您可能對 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

這是一個老問題,但我想我會為任何谷歌裁判添加這個問題的當前解決方案。

現在簽署和散列 JSON 對象的最佳方法是使用JSON Web Tokens 這允許對對象進行簽名、散列,然后由其他人根據簽名進行驗證。 它提供了一系列不同的技術,並有一個活躍的開發團隊。

您要求跨多種語言實現相同的東西......您幾乎肯定不走運。 您有兩個選擇:

  • 檢查 www.json.org 實現,看看它們是否可能更標准化
  • 在每種語言中推出自己的語言(使用 json.org 實現作為基礎,應該很少有工作要做)

您可以通過應用以下規則來規范化stringify()的結果:

  • 刪除不必要的空格
  • 對哈希中的屬性名稱進行排序
  • 定義明確的一致引用風格
  • 標准化字符串內容(因此“\A”和“A”變得相同)

這將為您留下對象的規范 JSON 表示,然后您可以可靠地對其進行散列。

在嘗試了一些哈希算法和 JSON-to-string 方法后,我發現這個方法效果最好(抱歉,它是 typescript,當然可以重寫為 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 位
  • 十六進制字符串結果
  • 最快(2177 B JSON 為 0.021 毫秒,150 kB JSON 為 2.64 毫秒)

您可能會發現bencode適合您的需求。 它是跨平台的,並且保證每個實現的編碼都是相同的。

缺點是它不支持空值或布爾值。 但是,如果您在編碼之前執行諸如轉換 bools -> 0|1和 nulls -> "null"類的操作,那對您來說可能沒問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM