Existe-t-il un moyen fiable de JSON.stringifier un objet JavaScript qui garantit que la chaîne JSON créée est la même sur tous les navigateurs, node.js et ainsi de suite, étant donné que l'objet Javascript est le même?
Je veux hacher des objets JS comme
{
signed_data: object_to_sign,
signature: md5(JSON.stringify(object_to_sign) + secret_code)
}
et les transmettre à travers les applications Web (par exemple Python et node.js) et l'utilisateur afin que l'utilisateur puisse s'authentifier auprès d'un service et afficher le prochain service "données signées" pour celui-ci à vérifier si les données sont authentiques.
Cependant, je suis tombé sur le problème que JSON.stringify n'est pas vraiment unique à travers les implémentations:
Existe-t-il une méthode de filtrage multiplateforme fiable? Existe-t-il un "JSON nomalisé"?
Recommanderiez-vous d'autres façons de hacher des objets comme celui-ci?
MISE À JOUR:
Voici ce que j'utilise comme solution de contournement:
normalised_json_data = JSON.stringify(object_to_sign)
{
signed_data: normalised_json_data,
signature: md5(normalised_json_data + secret_code)
}
Donc, dans cette approche, pas l'objet lui-même, mais sa représentation JSON (qui est spécifique à la plate-forme de signature) est signée. Cela fonctionne bien car ce que je signe maintenant est une chaîne sans ambiguïté et je peux facilement JSON.parse les données après avoir vérifié le hachage de signature.
L'inconvénient ici est que si j'envoie tout l'objet {signed_data, signature} sous forme de JSON, je dois appeler JSON.parse deux fois et il ne semble pas aussi agréable, car l'intérieur est échappé:
{"signature": "1c3763890298f5711c8b2ea4eb4c8833", "signed_data": "{\"user_id\":5}"}
Vous demandez qu'une implémentation de quelque chose dans plusieurs langues soit la même ... vous n'avez presque certainement pas de chance. Vous avez deux options:
Vous pourriez être intéressé par le paquet npm hash objet , qui semble avoir un assez bon niveau d'activité et de fiabilité.
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
C'est une vieille question, mais je pensais que j'ajouterais une solution actuelle à cette question pour tous les arbitres Google.
La meilleure façon de signer et de hacher des objets JSON est maintenant d'utiliser JSON Web Tokens . Cela permet à un objet d'être signé, haché puis vérifié par d'autres sur la base de la signature. Il est offert pour un tas de technologies différentes et dispose d'un groupe de développement actif.
Vous pouvez normaliser le résultat de stringify()
en appliquant des règles telles que:
Cela vous laisserait une représentation canonique JSON de votre objet, que vous pouvez ensuite hacher de manière fiable.
Après avoir essayé des algorithmes de hachage et des méthodes JSON en chaîne, j'ai trouvé que cela fonctionnait le mieux (Désolé, c'est TypeScript, peut bien sûr être réécrit en 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");
}
Il a utilisé le module npm: https://cyan4973.github.io/xxHash/ , https://www.npmjs.com/package/xxhash
Les avantages:
Vous pouvez trouver bencode adapté à vos besoins. Il est multiplateforme et le codage est garanti d'être le même à partir de chaque implémentation.
L'inconvénient est qu'il ne prend pas en charge les valeurs nulles ou booléennes. Mais cela peut vous convenir si vous faites quelque chose comme transformer, par exemple, bools -> 0|1
et null -> "null"
avant l'encodage.