日本語

開発者ツール · JSON フォーマッタおよびバリデータ

JSON ではキーの順序は重要ですか?順序付け、等価性、および RFC 8785

· 背景

json 規格 検証

JSON ではキーの順序は重要ですか? JSON トークンと正確な検証境界で示された順序付け、等価性、および RFC 8785
オリジナル ToolAcre ベクトル イラスト

JSON 仕様ではオブジェクトを順序付けせずに呼び出しますが、実際のパーサーとシリアライザーは通常順序を保持し、署名スキームは順序に依存します。この投稿では、仕様の内容、実装の機能、および正規化によって緊張がどのように解決されるかを解き明かします。

同じデータ、異なるバイト

`{"city":"Oslo","temp":4}` と `{"temp":4,"city":"Oslo"}` には同じ 2 つの名前と値が含まれていますが、ソース バイトが異なります。インデントにより、解析された値を変更することなく、さらに多くのテキストの違いを追加できます。そのため、「等しい JSON」には比較ルールが必要です。テキスト、解析されたオブジェクト、または別のプロトコルで定義された正規表現を比較していますか?

ToolAcre は、両方のドキュメントを同じインデントでフォーマットすることで空白ノイズを除去できます。このオプションが選択されている場合、オブジェクト キーを再帰的に並べ替えることもできます。並べ替えはメンバーの順序を意図的に変更しますが、配列の位置がデータを表すため、配列要素を移動することはありません。通常の書式設定もこのオプションの並べ替えも、RFC 8785 正規の JSON を生成しないため、出力を指定された署名形式で置き換えてはなりません。

RFC 8259 の内容 — オブジェクトは name/value ペアの順序付けされていないコレクションであり、実装は順序を公開する場合も公開しない場合もあります

RFC 8259 では、オブジェクトを name/value ペアの順序付けされていないコレクションとして説明します。したがって、メンバーの順序を通常の JSON オブジェクトの意味として扱うソフトウェアは、その抽象モデルの外側の動作に依存します。配列は明示的に順序付けされるため、`["draft","final"]` と `["final","draft"]` は互換性がありません。オブジェクトの順序と配列の順序を同じルールで正規化してはなりません。

RFC では、ライブラリがメンバーの順序付けを呼び出し元に公開するかどうかが異なることにも注意しています。移植可能な設計には、この警告で十分です。オブジェクト メンバーを別のオブジェクト メンバーの前に配置して優先順位や順序をエンコードしないでください。順序が重要な場合は、配列または明示的なフィールドで表します。安定した順序を示すフォーマッタは人間にとって便利ですが、位置をオブジェクトの標準レベルのプロパティに変換するわけではありません。

このフォーマッタが実際に行うこと

並べ替えを無効にすると、ToolAcre はドキュメントを解析し、結果の JavaScript 値をシリアル化します。出力は、元のトークン ストリームをバイト単位で保持するのではなく、JavaScript のプロパティ列挙動作に従います。ほとんどの通常の文字列キーはよく知られた順序で表示されますが、整数インデックスのような名前は他の名前より先に発行されることがあります。数値のスペルとエスケープの選択も、再シリアル化中に正規化できます。

並べ替えを有効にすると、フォーマッタは、ネストされたオブジェクトごとに独自のキーがアルファベット順に並べられた新しいオブジェクトを構築します。 `{"z":{"b":1,"a":2},"items":[{"d":4,"c":3},"x"]}` の場合、オブジェクト名は `items`、`z` になります。ネストされたオブジェクト名もソートされます。そして配列には `"x"` より前のオブジェクトがまだ含まれています。配列内のオブジェクトを並べ替えることは、配列自体を並べ替えることを意味しません。

バイト順序が重要な場合

プロセスが抽象値ではなく正確なバイトを消費する場合は常に、テキストの順序が重要になります。メンバーが移動したり空白が変更されたりすると、ファイル ハッシュ、キャッシュ キー、デジタル署名、または行ベースの差分が変更されます。これは順序なしオブジェクト モデルと矛盾しません。これは、周囲のプロセスが入力の一部としてバイト表現を選択したことを意味します。その場合、表現ルールは明示的かつ共有される必要があります。

日常的なレビューでは、一貫したインデントとオプションのアルファベット順の並べ替えを使用すると、変更が見やすくなります。暗号やプロトコルの作業では、「安定しているように見える」ということは契約ではありません。プロデューサーと検証者は、ハッシュまたは署名する前に、プロトコルで要求される正確な正規化アルゴリズムを使用する必要があります。アルゴリズムの名前が指定されていない場合は、ToolAcre の出力がバージョン、ランタイム、またはエッジケースの値を超えて別のシリアライザーと一致するとは想定しないでください。

キーのソートが RFC ではない理由 8785

RFC 8785 は、互換性のあるデータから反復可能なバイトを生成するための JSON 正規化スキームを定義します。その仕事はキーをアルファベット順に配置するよりも広範囲に及びます。これは、文字列と数値の正確なシリアル化動作とともに決定論的なプロパティの並べ替えを指定し、入力モデルに制約を課します。適切なインデントは正規の出力の一部ではなく、ロケールを意識した並べ替えは許容可能な近似値ではありません。

ToolAcre は RFC 8785 の主張を行っていません。その並べ替えオプションは、`JSON.parse` および `JSON.stringify` に重ねられた読みやすさ機能です。 I-JSON の前提条件を検証したり、RFC のシリアル化ルールを置き換えたりするものではありません。 `1e-7` などの値、非 ASCII 文字を含むキー、またはエスケープされた文字列により、カジュアルソートフォーマッタと準拠カノニカライザの違いが明らかになる可能性があります。 JCS が必要な場合は、テスト済みの JCS 実装を使用します。

作業例: 2 つのドキュメントを公平に比較する

`{"meta":{"rev":2,"owner":"Mira"},"steps":["cut","pack"]}` と `{"steps":["cut","pack"],"meta":{"owner":"Mira","rev":2}}` を比較します。両方を 2 つのスペースでフォーマットし、並べ替えを無効にします。空白スペースは一貫性を持ちますが、ルート メンバーとネストされたメンバーの順序は異なる場合があります。両方を解析し、目的のフィールドを比較して、生のテキストが等しいと宣言するのではなく、値レベルの同等性を確立します。

再帰キー ソートをオンにすると、両方の例が同じオブジェクト順序でレンダリングされますが、`steps` は `cut`、その後 `pack` のままになります。これは人間による差分には役立ちますが、それでも ToolAcre の正規化であり、RFC 8785 の証明ではありません。 2 番目の配列が `["pack","cut"]` であった場合、配列を変更すると表現されるシーケンスが変わるため、キーを並べ替えるとその違いが正しく表示されたままになります。

これでカバーされない内容

キーのソートは、すべてのアプリケーションに対して完全な同等性を定義するわけではありません。重複した名前は `JSON.parse` によって受け入れられ、最後の値が保持されるため、フォーマットによって 1 つのソースにリピートが含まれていたという証拠が消去される可能性があります。 JavaScript 値では、大きな整数の精度がすでに失われている可能性があります。ドメインは選択された配列をセットとして扱うこともありますが、ToolAcre はそのルールを推論できないため、配列の順序を変更することはありません。

フォーマッタは、スキーマの比較、デフォルトの適用、Unicode の正規化、または 2 つの数値表現がダウンストリーム システムで受け入れられるかどうかの判断も行いません。それらは別の契約です。プレゼンテーションのノイズを軽減するための書式設定、値の同一性のための専用の構造比較、および正確なバイトに対する指定されたカノニカライザーを使用します。これらのジョブを「正規化」という言葉の下で混ぜ合わせると、実際に比較されたものについて誤った信頼が生まれます。

要点: 順序はモデルにとっては重要ではありませんが、バイトにとっては重要です

RFC 8259 データ モデルでは、オブジェクト メンバーの順序は意味を持ちませんが、配列の順序は意味を持ちます。ソース バイトには順序と空白の両方が記録されるため、ハッシュ、署名、テキストの差分では、値指向の比較では無視される可能性のある区別が観察されます。ツールを選択する前に、どの層が重要であるかを述べてください。テキストの同一性、解析された値の等価性、およびプロトコル定義の正規の同一性は 3 つの異なる質問です。

ToolAcre は最初の 2 つのワークフローを間接的にのみサポートします。一貫した書式設定によりテキストの違いが明確になり、再帰的なアルファベット順のオブジェクト キー ソートにより人間による比較がより静かになります。配列は決してソートされません。結果は RFC 8785 正規の JSON ではないため、そうであるかのように署名するべきではありません。特に重複キーの解析では最後の値のみが保持されるため、語彙上の証拠が重要な場合は元の入力を保持します。