JSON解析
JSON解析ツールはブラウザ内でRFC 8259の構文を確認し、型ごとの件数、構造の深さ、言語間の型マッピングを表示します。元の数値トークンをJavaScriptのNumberに変換すると値が変わる箇所も示します。解析は元のテキストを変更せず、値を扱う変換ツールはそのような危険な変換を拒否します。
JSONドキュメントを貼り付けるか上の「例を試す」をクリックすると構造を解析できます。
JSON解析はどう動きますか?
「パースできるか?」という問いに答えるのはバリデーターです。このツールが答えるのはその次の問いで、たいていこちらのほうが興味深いものです。パースした結果、何になったのか?ドキュメントが完全に有効でも、コードが期待しているものとは別物であることがあり、そのズレは読むだけではほとんど見えません。
このパーサーはJSON.parseを呼び出さず、独自に実装しています。明示的な作業スタックを反復処理し、深くネストした文書を呼び出しスタックのオーバーフローなしに解析できます。ルート値の後の余分な内容は拒否します。各キーは保護したうえで独自のプロパティとして設定するため、__proto__はオブジェクトのプロトタイプを変更せず、通常のキーとして保持されます。
続いて分析はパース済みの値をたどり、そこにあるものを数えます。オブジェクト、配列、文字列、数値、真偽値、nullがそれぞれいくつあるか。ネストはどれだけ深いか。異なるキーはいくつ現れるか。これだけでも問題の特定には十分なことがよくあります。オブジェクトが入っているはずの配列に文字列しかない。スキーマが許すより3レベル深い構造。上流の結合に失敗して90%がnullになったドキュメント。といった具合です。
JSONの数値型は1つです。JavaScriptのJSON.parseは数値をIEEE-754のdoubleに変換し、すべての整数を正確に表せる範囲は2^53−1までです。例えば9007199254740993は、ネイティブの構文エラーなしに9007199254740992になります。この解析ツールは小数や指数を含む元の数値トークンを確認し、十進数の値が変わる箇所を変換のリスクとして示します。丸めた値を出力せずに構造を集計します。JSON整形ツールとJSON圧縮ツールは元のトークンを保持し、値を扱う変換ツールはこのような危険な数値を拒否します。
同じ表には、残りのマッピングも載っています。前提は言語ごとに異なるからです。Goは、型付きのstructにデコードしない限り、すべての数値をfloat64にします。Pythonはintとfloatを区別するため、大きな整数も正確に保ちます。JavaとC#は、設定すればBigDecimalやdecimalを用います。
ドキュメント
{ "id": 9007199254740993, "price": 0.1 }構造と数値のリスク
3 values · depth 1 · 2 distinct keys number 2 → number (IEEE-754 double) JavaScript Number conversion risk (source unchanged): 9007199254740993 → 9007199254740992
ドキュメント → 構造と数値のリスク
ドキュメント
{
"id": 42,
"name": "Ada"
"active": true
}構造と数値のリスク
Missing comma between object key-value pairs. Line 4, column 3 "active": true ^
JSON解析が対応するオプションとエッジケースは?
| パラメータ | 型 | デフォルト | 動作とエッジケース |
|---|---|---|---|
| 文法 | RFC 8259 | 厳格 | コメント、末尾カンマ、単一引用符、引用符のないキー、NaN、Infinityは使えません。これはJSONの構文規則であり、APIは別途スキーマやサイズ、数値の上限を設ける場合があります。JSON5とJSONCは拒否します。 |
| 末尾の余分な内容 | 拒否 | — | RFC 8259 §2では、ドキュメントは正確に1つの値と定義されています。連結された2つのオブジェクトは、誤って分割されたログ行の一般的な症状であり、最初に静かに切り捨てるのではなく報告されます。 |
| 数値の精度 | IEEE-754 | 検出時に表示 | 元の数値トークンをJavaScriptのNumberに変換して十進数として戻した値と比較します。値が変わる整数や小数、オーバーフロー、アンダーフローを検出します。元のテキストは変わらず、丸めた文書は出力しません。 |
| 重複キー | 最後のものが優先 | — | RFC 8259ではこれが未定義です。ほとんどのパーサーが最後の出現を保持しており、このパーサーもそれに一致します。チェーン内の2つのシステムが不一致の場合、実際の攻撃対象となるため、知っておくべきことです。 |
| __proto__ | 自身のプロパティ | — | defineProperty経由で割り当てられるため、プロトタイプを再指示するのではなく通常のキーになります。JSON.parseと一致しており、多くの手動パーサーが欠如しているガードです。 |
| ネストの深さ | 反復処理 | 上限なし | パーサーは明示的なスタックを使用するため、深さは呼び出しスタックではなくメモリによって制限されます。20,000レベルのドキュメントはテストでカバーされています。 |
| Unicode | UTF-8 | — | \uXXXXエスケープはデコードされ、サロゲートペアは再結合されるため、アストラル文字は保持されます。ルートの前のバイトオーダーマークはコンテンツとして扱われるのではなく報告されます。 |
| 入力サイズ | bytes | 8 MB | メインスレッドの上限。それを超えると、パーサーは試行されずに拒否されます。サイズに関係なく、何もアップロードされません。 |
よくある質問
これは「JSON検証」と何が違いますか?
検証ツールはJSONの構文エラーと修復に重点を置きます。この解析ツールは型ごとの件数、深さ、異なるキー、言語間のマッピング、数値変換のリスクも表示します。有効なJSONにもJavaScriptでは変換後に値が変わる数値を含められます。解析では文書を変更せず、元のトークンと、Number変換のプレビューであることを明示した値を表示します。
パースしたらIDの値が変わりました。何が起きたのですか?
JavaScriptの標準JSON.parseはIEEE-754の数値を使い、構文エラーなしに大きなIDを丸めることがあります。9007199254740993は9007199254740992になります。この解析ツールは元のトークンからそのリスクを示します。ToolsByUsの値変換ツールは桁が失われる変換を拒否し、整形ツールと圧縮ツールはテキストを保持します。システム間で正確なIDを渡すには文字列として送信するか、Pythonの標準JSONデコーダーのように任意精度の整数を扱えるパーサーを使ってください。
重複したキーがあるとどうなりますか?
最後のものが勝ちます。ほぼすべてのパーサーがそう動き、RFC 8259は規定を避けています。無視するより、知っておく価値があります。リクエストチェーン上の2つのシステムが重複を別々のやり方で解決すると、ある解釈で検証されたペイロードが、別の解釈で処理され得ます。これは現実に起こるセキュリティバグの類型です。
コメント入りのJSONが拒否されるのはなぜですか?
RFC 8259にはコメントがなく、厳格なパーサーの役割は、APIが何を受け付けるかを教えることだからです。ファイルが設定ファイルなら——tsconfig.json、.eslintrc.json——それはJSONCです。「JSON整形」はコメントと末尾カンマを受け付け、除去することもできます。
パース後の0.1は正確に0.1ですか?
いいえ。これはJSONの問題ではなく、2進浮動小数点の問題です。0.1は、どの言語でもdoubleとして正確に表現できません。だからこそ0.1 + 0.2が0.3にならないのは有名です。通貨では、整数の補助単位(ペニー、セント)か10進の文字列で持ち、floatを使わないのが定石です。
ドキュメントはどこかに送信されますか?
いいえ。文書をアップロードせず、解析をブラウザ内で実行します。このページと必要なファイルの読み込み後は、JSON解析自体はネットワーク接続なしで動作します。