JSON RFC 8259 : les détails subtils qui font trébucher les parseurs de production

JSON est plus petit que tu ne le crois

La grammaire JSON de la RFC 8259 est minuscule : objets, tableaux, chaînes, nombres, et les trois littéraux true, false et null. Cette simplicité explique son omniprésence — et aussi pourquoi deux surprises prennent les gens de court. D'abord, n'importe quelle valeur peut être le document entier : 42, "hello" et true sont chacun un JSON complet et valide. L'ancienne RFC 4627 exigeait que le niveau supérieur soit un objet ou un tableau, donc certains outils hérités rejettent encore une valeur nue.

Ensuite, la spécification laisse délibérément plusieurs comportements non spécifiés. Elle définit la syntaxe précisément mais dit peu sur les clés en double, la précision des nombres ou l'ordre. Les parseurs de production comblent ces vides différemment, et c'est exactement là que vivent les bugs d'interopérabilité.

Clés en double : comportement indéfini

La RFC 8259 dit que les noms d'objet DEVRAIENT (SHOULD) être uniques, pas qu'ils DOIVENT (MUST) l'être. Quand une clé se répète, le résultat n'est pas spécifié, donc les parseurs divergent : la plupart prennent la dernière valeur, certains gardent la première, quelques-uns lèvent une erreur, et un rare garde les deux. Aucun n'a tort selon la spec.

C'est un vrai risque de sécurité. Si un service valide {"role":"user","role":"admin"} en lisant le premier role et qu'un autre agit sur le dernier, un attaquant peut faire passer un privilège au travers de la validation. Traite les clés en double comme une erreur là où la décision compte, et ne dépends jamais de la valeur qui « gagne ».

Nombres : pas d'entiers, que des ennuis

JSON a un seul type de nombre. La RFC ne définit ni précision ni plage — elle note seulement que, pour l'interopérabilité, on attend des implémentations qu'elles gèrent les valeurs tenant en double précision IEEE 754. En pratique, cela signifie que tout au-dessus de 2^53 (soit 9007199254740992) peut perdre en précision.

Le bug classique : un ID 64 bits comme 9007199254740993 devient 9007199254740992 après JSON.parse en JavaScript, car les nombres sont des doubles. La solution est de transporter les grands entiers sous forme de chaînes. Quelques règles encore oubliées : pas de zéros en tête (007 est invalide), pas de + initial, pas de point décimal final (1. est invalide), et NaN et Infinity ne sont pas du JSON valide — sérialise-les en null ou en chaîne.

Chaînes, Unicode et encodage

Les chaînes doivent utiliser des guillemets doubles, et les caractères de contrôle de U+0000 à U+001F doivent être échappés. La barre oblique peut être échappée optionnellement en \/, c'est pourquoi certains encodeurs émettent <\/script> — une façon légale de ne pas casser une balise script HTML. La RFC 8259 impose l'UTF-8 pour le JSON échangé entre systèmes.

Les caractères hors du Plan Multilingue de Base (BMP), comme la plupart des emoji, s'écrivent en une paire de substitution (surrogate) d'échappements \u plutôt qu'un seul. Les substituts isolés, non appariés, sont techniquement invalides, mais certains parseurs les acceptent — un piège de portabilité qui ne surgit que lorsque tes données passent dans une implémentation plus stricte.

Ce qui ressemble à du JSON mais n'en est pas

Les erreurs les plus courantes viennent de traiter JSON comme du JavaScript. Les virgules finales sont invalides. Les commentaires n'existent pas en JSON — JSON5 et JSONC les ajoutent, mais un parseur strict RFC 8259 les rejettera. Les chaînes à guillemets simples et les clés d'objet sans guillemets sont aussi invalides, aussi familières soient-elles.

Plus subtil : la marque d'ordre des octets (BOM). La RFC 8259 dit que les producteurs NE DOIVENT PAS (MUST NOT) ajouter de BOM et que les consommateurs PEUVENT (MAY) en ignorer une, mais la BOM ne fait pas partie de JSON, donc une BOM UTF-8 en début de fichier peut faire échouer un parseur strict dès le premier octet. L'espace blanc insignifiant se limite à l'espace, la tabulation, le saut de ligne et le retour chariot — rien d'autre.

À retenir

Rejette les clés en double là où une décision de sécurité ou d'exactitude dépend de la valeur.

Transporte les entiers 64 bits sous forme de chaînes pour qu'ils survivent aux parseurs en double précision comme celui de JavaScript.

Ne dépends pas de l'ordre des clés d'objet — la spec définit les objets comme non ordonnés, même si la plupart des parseurs conservent l'ordre d'insertion.

Souviens-toi que n'importe quelle valeur est du JSON de niveau supérieur valide sous la RFC 8259, pas seulement les objets et tableaux.

Si tu veux des commentaires ou des virgules finales, tu veux JSON5/JSONC — convertis avant qu'un parseur strict ne voie les données. Le formateur JSON de ce site valide contre la grammaire stricte de la RFC 8259, donc ces problèmes surgissent immédiatement.