Comment cryptographier un objet JSON?

la question suivante est plus complexe qu'il n'y paraît.

supposons que j'ai un objet JSON arbitraire, qui peut contenir n'importe quelle quantité de données incluant d'autres objets JSON imbriqués. Ce que je veux, c'est un hachage cryptographique/condensé des données JSON, sans tenir compte du formatage JSON proprement dit (par exemple: ignorer les nouvelles lignes et les différences d'espacement entre les jetons JSON).

la dernière partie est une exigence, car le JSON sera généré/lu par une variété de (de)sérialiseurs sur un certain nombre de plates-formes différentes. Je connais au moins une bibliothèque JSON pour Java qui supprime complètement le formatage lors de la lecture de données pendant la desérialisation. En tant que tel, il brisera le hachage.

la clause de données arbitraires ci-dessus complique également les choses, car elle m'empêche de prendre des champs connus dans un ordre donné et de les concaténer avant de les poursuivre (pensez à peu près comment fonctionne la méthode hashCode() Non cryptographique de Java).

enfin, il n'est pas non plus souhaitable de hacher toute la chaîne JSON en un morceau d'octets (avant la desérialisation), car il y a des champs dans le JSON qui devraient être ignorés lors du calcul du hachage.

Je ne suis pas sûr qu'il y ait une bonne solution à ce problème, mais je me réjouis de toutes les approches ou pensées=)

46
demandé sur Jason Nichols 2011-01-12 18:25:39

6 réponses

le problème est commun lorsque l'on calcule des hachures pour n'importe quel format de données où la flexibilité est permise. Pour résoudre cela, vous devez canoniser la représentation.

par exemple, le OAuth1.Le protocole 0a, qui est utilisé par Twitter et d'autres services pour l'authentification, nécessite un hachage sécurisé du message de demande. Pour calculer le hachage, OAuth1.0a dit que vous devez d'abord alphabétiser les champs, les séparer par des nouvelles lignes, supprimer le champ les noms (qui sont bien connus), et utilisez des lignes vides pour les valeurs vides. La signature ou le hachage est calculé sur le résultat de cette canonisation.

XML dsig fonctionne de la même manière - vous devez canoniser le XML avant de le signer. Il y a une norme proposée Pour le W3 couvrant ce , parce que c'est une exigence fondamentale pour la signature. Certains l'appellent c14n.

Je ne connais pas de norme de canonisation pour json. C'est valeur de la recherche.

s'il n'y en a pas, vous pouvez certainement établir une convention pour votre application particulière. Un départ raisonnable pourrait être:

  • classez les propriétés par leur nom au niveau lexicographique
  • double guillemets utilisés sur tous les noms
  • guillemets doubles utilisés sur toutes les valeurs de chaîne de caractères
  • aucun espace, ou un espace, entre les noms et le colon, et entre le colon et la valeur
  • pas d'espace entre les valeurs et la virgule suivante
  • tous les autres espaces blancs se sont effondrés en un seul espace ou rien-choisir un
  • exclure toutes les propriétés que vous ne voulez pas signer (un exemple est la propriété qui détient la signature elle-même)
  • signe le résultat, avec l'algorithme que vous avez choisi

vous pouvez également penser à la façon de passer cette signature dans l'objet JSON-peut-être établir un nom de propriété bien connu, comme "nichols-hmac" ou quelque chose, qui obtient la version encodée base64 du hachage. Cette propriété devrait être expressément exclus par l'algorithme de hachage. Alors, n'importe quel receveur du JSON serait capable de vérifier le hachage.

la représentation canonisée n'a pas besoin d'être la représentation que vous faites circuler dans la demande. Il doit uniquement être facilement produit donné un objet JSON arbitraire.

41
répondu Cheeso 2015-07-21 22:03:57

au lieu d'inventer votre propre normalisation JSON/canonicalisation, vous pouvez utiliser bencode . Sémantiquement, c'est la même chose que JSON (composition de nombres, chaînes, listes et dicts), mais avec la propriété d'encodage non ambigu qui est nécessaire pour le hachage cryptographique.

bencode est utilisé comme format de fichier torrent, chaque client bittorrent contient une implémentation.

5
répondu Nikita Nemkin 2017-08-27 20:29:32

il s'agit du même problème que celui qui cause des problèmes avec les signatures S/MIME et XML. C'est, il y a de multiples représentations équivalentes des données à signer.

par exemple dans JSON:

{  "Name1": "Value1", "Name2": "Value2" }

vs.

{
    "Name1": "Value\u0031",
    "Name2": "Value\u0032"
}

ou selon votre application, cela peut même être équivalent:

{
    "Name1": "Value\u0031",
    "Name2": "Value\u0032",
    "Optional": null
}

la canonisation pourrait résoudre ce problème, mais c'est un problème dont vous n'avez pas besoin à tous.

la solution facile si vous avez le contrôle sur la spécification est d'envelopper l'objet dans une sorte de récipient pour le protéger d'être transformé en un" équivalent " mais représentation différente.

i. e. évitez le problème en ne signant pas l'objet "logique" mais en signant une représentation particulière sérialisée de celui-ci à la place.

par exemple, JSON Objects -> UTF-8 Text -> Bytes. Signer les octets comme octets , puis les transmettre en octets , p.ex. par encodage base64. Puisque vous signez les octets, les différences comme les espaces font partie de ce qui est signé.

au Lieu d'essayer de faire ceci:

{  
   "JSONContent": {  "Name1": "Value1", "Name2": "Value2" },
   "Signature": "asdflkajsdrliuejadceaageaetge="
}

faites Simplement ceci:

{
   "Base64JSONContent": "eyAgIk5hbWUxIjogIlZhbHVlMSIsICJOYW1lMiI6ICJWYWx1ZTIiIH0s",
   "Signature": "asdflkajsdrliuejadceaageaetge="

}

i. e. ne signez pas le JSON, signez les octets codés JSON.

Oui, cela signifie que la signature n'est plus transparent.

3
répondu Ben 2016-12-06 14:17:16

JSON-LD peut faire de la normalisation.

vous devrez définir votre contexte.

2
répondu jbaylina 2015-01-31 08:28:16

je ferais tous les champs dans un ordre donné (alphabétiquement par exemple). Pourquoi des données arbitraires faire une différence? Vous pouvez simplement itérer sur les propriétés (réflexion ala).

alternativement, je chercherais à convertir la chaîne de JSON brute en une forme canonique bien définie ( supprimer tout le formatage superflous) - et le hachage que.

0
répondu RasmusKL 2011-01-12 15:37:05

nous avons rencontré un problème simple avec le hachage de charges utiles codées JSON. Dans notre cas, nous utilisons la méthodologie suivante:

  1. Convertissez les données en objet JSON;
  2. Encoder en JSON charge utile en base64
  3. Message digest (HMAC) générés base64 de la charge utile .
  4. transmettez la charge base64 .

avantages de cette solution:

  1. Base64 produira la même sortie pour une charge utile donnée.
  2. étant donné que la signature résultante sera dérivée directement de la charge utile encodée en base64 et que la charge utile en base64 sera échangée entre les points terminaux, nous serons certains que la signature et la charge utile seront maintenues.
  3. cette solution résout les problèmes qui se posent en raison de différences dans l'encodage des caractères spéciaux.

désavantages

  1. l'encodage / le décodage de la charge utile peut ajouter un
  2. "
  3. les données codées selon la Base64 sont habituellement de 15 à 20% plus grandes que la charge utile originale.
0
répondu Deezzle LuBimkii 2018-04-05 02:28:53