你是对的
-
BOM 字符在 JSON 中是非法的(不需要)
-
MIME 字符集在 JSON 中是非法的(也不需要)
RFC 7159, Section 8.1:
实现不得在 JSON 文本的开头添加字节顺序标记。
尽可能清楚地说明这一点。这是整个 RFC 中唯一的“不得”。
RFC 7159, Section 11:
JSON 文本的 MIME 媒体类型是 application/json。
类型名称:应用程序
子类型名称:json
必需参数:不适用
可选参数:不适用
[...]
注意:没有为此注册定义“charset”参数。
JSON 编码
JSON 唯一有效的编码是 UTF-8、UTF-16 或 UTF-32,因为第一个字符(如果有多个字符,则为前两个)的 Unicode 值总是低于 128(有没有可以包含前两个字符的更高值的有效 JSON 文本)总是可以通过查看字节流来知道使用了哪种有效编码和哪种字节序。
RFC 推荐
JSON RFC 规定前两个字符将始终低于 128,您应该检查前 4 个字节。
我会换一种说法:因为字符串“1”也是有效的 JSON,所以不能保证你有两个字符 - 更不用说 4 个字节了。
我的建议
我对确定 JSON 编码的建议会略有不同:
快速方法:
- 如果您有 1 个字节并且它不是 NUL - 它是 UTF-8
(实际上这里唯一有效的字符是 ASCII 数字)
- 如果您有 2 个字节并且它们都不是 NUL - 它是 UTF-8
(必须是不带前导“0”的 ASCII 数字、{}、[] 或 "")
- 如果您有 2 个字节并且只有第一个字节是 NUL - 它是 UTF-16BE
(必须是编码为 UTF-16、大端序的 ASCII 数字)
- 如果您有 2 个字节并且只有第二个字节是 NUL - 它是 UTF-16LE
(它必须是编码为 UTF-16、小端序的 ASCII 数字)
- 如果您有 3 个字节并且它们不是 NUL - 它是 UTF-8
(同样,没有前导 '0' 的 ASCII 数字、"x"、[1] 等)
- 如果您有 4 个字节或超过 RFC 方法的工作量:
-
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 字符集 - 两者都不需要并且 在 JSON 中无效。
您只需要在使用 UTF-16 和 UTF-32 时使用二进制内容传输编码,因为它们可能包含 NUL 字节。 UTF-8 没有这个问题,并且 8 位内容传输编码很好,因为它在字符串中不包含 NUL(尽管它仍然包含字节 >= 128,所以 7 位传输将不起作用 - 有 UTF- 7 适用于此类传输,但它不是有效的 JSON,因为它不是唯一有效的 JSON 编码之一。
有关详细信息,另请参阅this answer。
回答您的后续问题
这些推论正确吗?
是的。
在实施符合这种解释的网络服务或网络客户端时,我会遇到问题吗?
可能,如果您与不正确的实现进行交互。为了与不正确的实现互操作,您的实现可能会忽略 BOM - 请参阅RFC 7159, Section 1.8:
为了互操作性,实施
解析 JSON 文本的可能会忽略字节顺序标记的存在
而不是将其视为错误。
此外,忽略 MIME 字符集是合规 JSON 实现的预期行为 - 请参阅 RFC 7159, Section 11:
注意:没有为此注册定义“charset”参数。
添加一个确实对合规收件人没有影响。
安全注意事项
我个人并不认为总是需要默默地接受不正确的 JSON 流。如果您决定接受带有 BOM 和/或 MIME 字符集的输入,那么您必须回答这些问题:
- 如果 MIME 字符集和实际编码不匹配怎么办?
- 如果 BOM 和 MIME 字符集不匹配怎么办?
- 如果 BOM 与实际编码不匹配怎么办?
- 当它们都不同时该怎么办?
- 如何处理除 UTF-8/16/32 以外的编码?
- 您确定所有安全检查都会按预期进行吗?
在三个独立的地方定义编码 - 在 JSON 字符串本身、BOM 和 MIME 字符集中,这使得问题不可避免:如果他们不同意该怎么办。除非你拒绝这样的输入,否则没有一个明显的答案。
例如,如果您有一个验证 JSON 字符串的代码,以查看在 JavaScript 中对其进行评估是否安全 - 它可能会被 MIME 字符集或 BOM 误导,并将其视为与实际不同的编码,并且如果使用正确的编码,则不检测它会检测到的字符串。 (过去 HTML 的一个类似问题导致了 XSS 攻击。)
当您决定接受具有多个且可能相互冲突的编码指示符的错误 JSON 字符串时,您必须为所有这些可能性做好准备。这并不是说您永远不应该这样做,因为您可能需要使用由不正确的实现生成的输入。我只是说你需要彻底考虑其中的含义。
不合格的实现
我应该针对违反上述两个属性的网络浏览器提交错误吗?
当然 - 如果他们称它为 JSON 并且实现不符合 JSON RFC,那么这是一个错误,应该这样报告。
您是否发现任何不符合 JSON 规范的特定实现,但他们宣传这样做?