如何可靠地散列JavaScript对象?

时间:2011-04-05 23:20:30

标签: javascript json node.js hash

是否有JSON.stringify,因为JavaScript对象是一样的吗?一个JavaScript对象,它保证了ceated JSON字符串是在所有浏览器,Node.js的等相同的可靠方式

我想散列像

这样的JS对象
{
  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”?

你会推荐其他方法来散列像这样的对象吗?

更新

这是我用作解决方法的方法:

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

因此,在该方法中,不是对象本身,但它的JSON表示(这是特定于sigining平台)进行签名。这个效果很好,因为我现在的标志是一个明确的字符串,我可以很容易地JSON.parse数据我已经检查了签名中的散列后。

这里的缺点是,如果我将整个{signed_data,signature}对象作为JSON发送,我必须两次调用JSON.parse并且它看起来不太好,因为内部对象被转义:

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

6 个答案:

答案 0 :(得分:31)

你可能对npm package 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

答案 1 :(得分:7)

这是一个老问题,但我想我会为任何谷歌裁判添加当前的解决方案。

现在签名和散列JSON对象的最佳方法是使用JSON Web Tokens。这允许对象基于签名进行签名,散列,然后由其他人验证。它提供了许多不同的技术,并且有一个活跃的开发小组。

答案 2 :(得分:5)

你要求跨多种语言的实现是相同的...你几乎肯定是运气不好。您有两种选择:

  • 查看www.json.org实施,看看它们是否可能更标准化
  • 使用每种语言自己动手(使用json.org实现作为基础,应该做很少的工作)

答案 3 :(得分:4)

您可以通过应用以下规则来规范化stringify()的结果:

  • 删除不必要的空格
  • 在哈希中对属性名称进行排序
  • 明确定义的一致引用样式
  • 规范化字符串内容(因此“\ u0041”和“A”变得相同)

这将为您提供对象的规范JSON表示,然后您可以可靠地散列。

答案 4 :(得分:1)

尝试了一些哈希算法和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位
  • 十六进制字符串为结果
  • 最快(对于2177 B JSON为0.021毫秒,对于150 kB JSON为2.64毫秒)

答案 5 :(得分:0)

您可能会发现bencode适合您的需求。它是跨平台的,并且保证每种实现的编码都相同。

缺点是它不支持null或booleans。但是,如果您在编码之前进行了一些转换,例如bools-> renderText(3, 5, t, 9, [ { 'path': 'C:\\Users\\User\\Downloads\\NotoSans-hinted\\NotoSans-Regular.ttf', # Font path 'name': 'Noto Sans' # Font name }, { 'path': 'C:\\Users\\User\\Downloads\\NotoSansSymbols2-unhinted\\NotoSansSymbols2-Regular.ttf', 'name': 'Noto Sans Symbols2' } ] , 0.08) # The distance between the letters plt.show() 和null-> 0|1,那对您来说可能就可以了。