有没有一种可靠的方法来JSON.stringify一个JavaScript对象,保证所有浏览器,node.js等的ceated JSON字符串是相同的,因为Javascript对象是相同的?
我想哈希JS对象
{
signed_data: object_to_sign,
signature: md5(JSON.stringify(object_to_sign) + secret_code)
}
并将它们传递给Web应用程序(例如Python和node.js)和用户,以便用户可以针对一个服务进行身份验证,并为该服务显示下一个服务“签名数据”,以检查数据是否可信。
但是,我遇到了JSON.stringify在实现中并不是唯一的问题:
有可靠的跨平台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}"}
你要求跨多种语言的实现是相同的...你几乎肯定是运气不好。您有两种选择:
您可能对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
这是一个老问题,但我想我会为任何谷歌裁判添加当前的解决方案。
现在签名和散列JSON对象的最佳方法是使用JSON Web Tokens。这允许对象基于签名进行签名,散列,然后由其他人验证。它提供了一系列不同的技术,并拥有一个活跃的开发小组。
您可以通过应用以下规则来规范化stringify()
的结果:
这将为您提供对象的规范JSON表示,然后您可以可靠地散列。
在尝试了一些哈希算法和JSON到字符串的方法之后,我发现这是最好的(抱歉,它是打字稿,当然可以改写为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
好处:
您可能会发现bencode适合您的需求。它是跨平台的,并且每个实现都保证编码相同。
缺点是它不支持空值或布尔值。但是,如果您在编码之前执行类似转换的操作,例如bools - > 0|1
和nulls - > "null"
,那么这对您可能没问题。