あなたが正しいです
- BOM 文字は JSON では不正です(必要ありません)
- MIME 文字セットは JSON では違法です(また、必要ありません)
RFC 7159、セクション 8.1 :
実装は、JSON テキストの先頭にバイト オーダー マークを追加してはなりません。
これは可能な限り明確に記載されています。これは、RFC 全体で唯一の「MUST NOT」です。
RFC 7159、セクション 11 :
JSON テキストの MIME メディア タイプは application/json です。
タイプ名: アプリケーション
サブタイプ名: json
必須パラメータ: n/a
オプション パラメータ: n/a
[...]
注意: この登録には「charset」パラメータは定義されていません。
JSON エンコーディング
JSON の唯一の有効なエンコーディングは UTF-8、UTF-16、または UTF-32 であり、最初の文字 (複数の文字がある場合は最初の 2 つ) は常に 128 未満の Unicode 値を持つため (有効な JSON はありません)最初の 2 文字のより高い値を含むことができるテキスト) バイト ストリームを見るだけで、どの有効なエンディアンが使用されたか、どのエンディアンが使用されたかを常に知ることができます。
RFC 勧告
JSON RFC によると、最初の 2 文字は常に 128 未満であり、最初の 4 バイトを確認する必要があります。
私は別の言い方をします: 文字列 "1" も有効な JSON であるため、4 バイトどころか 2 文字であるという保証はありません。
私のおすすめ
JSON エンコーディングの決定に関する私の推奨事項は、少し異なります。
高速な方法:
- 1バイトでNULでない場合-UTF -8
です(実際、ここで有効な文字はASCII数字のみです)
- 2 バイトがあり、いずれも NUL でない場合 - それはUTF-8です (先頭に '0' 、、、または
のない ASCII 数字でなければなりません){}
[]
""
- 2 バイトがあり、最初のバイトだけが NUL の場合 - UTF-16BE
です (UTF-16、ビッグエンディアンとしてエンコードされた ASCII 数字でなければなりません)
- 2 バイトがあり、2 番目だけが NUL の場合 - UTF-16LE
です (UTF-16、リトルエンディアンとしてエンコードされた ASCII 数字でなければなりません)
- 3 バイトがあり、それらが NUL でない場合 - UTF-8
です (ここでも、先行する '0' のない ASCII 数字"x"
、[1]
など)。
- RFC メソッドが機能するよりも 4 バイト以上ある場合:
00 00 00 xx
- UTF-32BE です
00 xx 00 xx
- UTF-16BE です
xx 00 00 00
- UTF-32LE です
xx 00 xx 00
- UTF-16LE です
xx xx xx xx
- UTF-8 です
ただし、これらのエンコーディングのいずれかで実際に有効な文字列である場合にのみ機能しますが、そうでない場合もあります。さらに、5 つの有効なエンコーディングのいずれかに有効な文字列がある場合でも、有効な JSON ではない可能性があります。
私の推奨事項は、RFC に含まれているものよりも少し厳格な検証を行って、次のことを確認することです。
- UTF-8、UTF-16、または UTF-32 (LE または BE) のいずれかの有効なエンコーディング
- 有効な JSON
NUL バイトだけを探すだけでは十分ではありません。
そうは言っても、エンコーディングを決定するために BOM 文字を使用する必要はありません。また、MIME charset も必要ありません。どちらも不要であり、 JSON では有効ではありません。
UTF-16 および UTF-32 を使用する場合は、NUL バイトが含まれている可能性があるため、バイナリの content-transfer-encoding のみを使用する必要があります。UTF-8 にはその問題はなく、文字列に NUL が含まれていないため、8 ビットの content-transfer-encoding で問題ありません (ただし、128 以上のバイトが含まれているため、7 ビットの転送は機能しません - UTF があります)。 7 はそのような転送には機能しますが、有効な JSON エンコーディングの 1 つだけではないため、有効な JSON ではありません)。
詳細については、この回答も参照してください。
フォローアップの質問に答える
これらの控除は正しいですか?
はい。
この解釈に従う Web サービスまたは Web クライアントを実装するときに問題が発生しますか?
おそらく、不適切な実装とやり取りした場合。実装は、正しくない実装との相互運用性のために BOM を無視してもよい (MAY) - RFC 7159, Section 1.8を参照:
相互運用性のために、JSON テキストを解析する実装は、バイト オーダー マークをエラーとして扱うのではなく、その存在を無視してもよい[MAY]。
また、MIME 文字セットを無視することは、準拠する JSON 実装の予期される動作です。RFC 7159、セクション 11を参照してください。
注: この登録には「charset」パラメータは定義されていません。1 つ追加しても、準拠している受信者にはまったく影響しません。
セキュリティに関する考慮事項
私は個人的に、正しくない JSON ストリームを黙って受け入れることが常に望まれているとは確信していません。BOM および/または MIME 文字セットを使用した入力を受け入れることにした場合は、次の質問に答える必要があります。
- MIME 文字セットと実際のエンコーディングが一致しない場合はどうすればよいですか?
- BOM と MIME 文字セットが一致しない場合はどうすればよいですか?
- BOM と実際のエンコーディングが一致しない場合はどうすればよいですか?
- それらすべてが異なる場合はどうすればよいですか?
- UTF-8/16/32 以外のエンコーディングはどうすればよいですか?
- すべてのセキュリティ チェックが期待どおりに機能することを確信していますか?
エンコーディングを 3 つの独立した場所 (JSON 文字列自体、BOM、MIME 文字セット) で定義すると、問題が避けられなくなります。そして、そのような入力を拒否しない限り、明確な答えはありません。
たとえば、JSON 文字列を検証して JavaScript で安全に評価できるかどうかを確認するコードがある場合、MIME 文字セットまたは BOM によって誤解され、実際とは異なるエンコーディングとして扱われ、文字列が検出されない可能性があります。正しいエンコーディングを使用しているかどうかを検出します。(HTML に関する同様の問題が、過去に XSS 攻撃につながったことがあります。)
複数の競合する可能性のあるエンコーディング インジケーターを含む誤った JSON 文字列を受け入れることにした場合は、これらすべての可能性に備える必要があります。間違った実装によって生成された入力を消費する必要があるかもしれないので、決してそうすべきではないと言っているわけではありません。その影響を十分に検討する必要があると言っているだけです。
不適合な実装
上記の 2 つの特性に違反する Web ブラウザーに対してバグを報告する必要がありますか?
確かに - 彼らがそれを JSON と呼び、実装が JSON RFC に準拠していない場合、それはバグであり、そのように報告する必要があります。
JSON 仕様に準拠していない特定の実装を見つけましたが、それを宣伝していますか?