How to reliably hash JavaScript objects?

前端 未结 6 1851
天涯浪人
天涯浪人 2021-02-06 21:53

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 Java

相关标签:
6条回答
  • 2021-02-06 22:32

    After trying some hash algorithms and JSON-to-string methods, I found this to work the best (Sorry, it is typescript, can of course be rewritten to 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");
    }
    

    It used npm module: https://cyan4973.github.io/xxHash/ , https://www.npmjs.com/package/xxhash

    The benefits:

    • This is deterministic
    • Ignores key order (preserves array order)
    • Cross platform (if you can find equivalents for JSON-stringify) JSON-stringify will hopefully will not get a different implementation and the whitespace removal will hopefully make it JSON-formatting independent.
    • 64-bit
    • Hexadecimal string a result
    • Fastest (0.021 ms for 2177 B JSON, 2.64 ms for 150 kB JSON)
    0 讨论(0)
  • 2021-02-06 22:33

    This is an old question, but I thought I'd add a current solution to this question for any google referees.

    The best way to sign and hash JSON objects now is to use JSON Web Tokens. This allows for an object to be signed, hashed and then verified by others based on the signature. It's offered for a bunch of different technologies and has an active development group.

    0 讨论(0)
  • 2021-02-06 22:35

    You could normalise the result of stringify() by applying rules such as:

    • remove unnecessary whitespace
    • sort attribute names in hashes
    • well-defined consistent quoting style
    • normalise string contents (so "\u0041" and "A" become the same)

    This would leave you with a canonical JSON representation of your object, which you can then reliably hash.

    0 讨论(0)
  • 2021-02-06 22:41

    You're asking for an implementation of something across multiple languages to be the same... you're almost certainly out of luck. You have two options:

    • check www.json.org implementations to see if they might be more standardized
    • roll your own in each language (use json.org implementations as a base and there should be VERY little work to do)
    0 讨论(0)
  • 2021-02-06 22:41

    You might be interested in npm package object-hash, which seems to have a rather good activity & reliability level.

    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
    
    0 讨论(0)
  • 2021-02-06 22:41

    You may find bencode suitable for your needs. It's cross-platform, and the encoding is guaranteed to be the same from every implementation.

    The downside is it doesn't support nulls or booleans. But that may be okay for you if you do something like transforming e.g., bools -> 0|1 and nulls -> "null" before encoding.

    0 讨论(0)
提交回复
热议问题