JavaScriptオブジェクトが同じであれば、作成されたJSON文字列がすべてのブラウザー、node.jsなどで同じであることを保証するJavaScriptオブジェクトをJSON.stringifyする信頼できる方法はありますか?
私はJSオブジェクトをハッシュしたい
{
signed_data: object_to_sign,
signature: md5(JSON.stringify(object_to_sign) + secret_code)
}
そして、それらをWebアプリケーション(Python and node.js)など)とユーザー全体に渡して、ユーザーが1つのサービスに対して認証し、そのサービスの次のサービスの「署名付きデータ」を確認できるようにします。データが本物である場合。
しかし、JSON.stringifyは実装全体で実際には一意ではないという問題に遭遇しました。
信頼できるクロスプラットフォームの文字列化メソッドはありますか? 「正規化されたJSON」はありますか?
このようなオブジェクトをハッシュする他の方法をお勧めしますか?
更新:
これは私が回避策として使用するものです:
normalised_json_data = JSON.stringify(object_to_sign)
{
signed_data: normalised_json_data,
signature: md5(normalised_json_data + secret_code)
}
したがって、このアプローチでは、オブジェクト自体ではなく、JSON表現(署名プラットフォームに固有)が署名されます。これでうまくいきます。今署名するのは一義的な文字列であり、署名ハッシュを確認した後でデータを簡単にJSON.parseできるからです。
ここでの欠点は、{signed_data、signature}オブジェクト全体をJSONとしても送信する場合、JSON.parseを2回呼び出す必要があり、内部のオブジェクトがエスケープされるため、JSON.parseのように見えないことです。
{"signature": "1c3763890298f5711c8b2ea4eb4c8833", "signed_data": "{\"user_id\":5}"}
あなたは複数の言語にわたる何かの実装が同じであることを求めています...あなたはほぼ確実に運が悪いです。次の2つのオプションがあります。
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
これは古い質問ですが、Googleのレフリーのために、この質問に現在の解決策を追加したいと思いました。
JSONオブジェクトに署名してハッシュする最善の方法は、 JSON Web Tokens を使用することです。これにより、オブジェクトは署名され、ハッシュされ、署名に基づいて他のユーザーによって検証されます。さまざまなテクノロジーに対応しており、活発な開発グループがあります。
次のようなルールを適用することにより、stringify()
の結果を正規化できます。
これにより、オブジェクトの正規の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
メリット:
bencode がニーズに適している場合があります。これはクロスプラットフォームであり、エンコーディングはすべての実装で同じであることが保証されています。
欠点は、nullまたはブール値をサポートしないことです。しかし、たとえばブール値-> 0|1
とnull-> "null"
エンコードする前。