简体中文

开发者工具 · JSON 格式化程序和验证程序

JSON 中的重复键:RFC 8259 允许什么以及解析器做什么

· 背景

json 标准 验证

JSON 中的重复键:RFC 8259 允许什么以及解析器通过 JSON 标记和精确的验证边界进行说明
原始 ToolAcre 矢量图

JSON 的语法允许相同的键两次,规范只说名称“应该”是唯一的,并且解析器对于哪个值获胜存在分歧。这篇文章解释了为什么这对于正确性和安全性很重要。

服务器读取了哪个“角色”?

考虑 `{"role":"viewer","role":"editor"}`。两个成员在语法上都是完整的,因此 ToolAcre 报告有效的 JSON。当文本到达 `JSON.parse` 时,生成的对象具有一个 `role` 属性,其值为 `"editor"`。较早的成员不会保留为隐藏历史记录。因此,成功的语法检查不会回答对象名称是否出现多次的问题。

格式化使丢失仅在发生后才可见:输出在所选布局中包含 `{"role":"editor"}`。它无法重现丢弃的 `viewer` 成员,因为序列化接收的是解析后的对象,而不是原始成员序列。如果重复的名称对审阅很重要,请在按“格式”之前保留并检查源文本,而不是依赖标准化结果。

语法允许,规范不鼓励

RFC 8259 表示对象内的名称应该是唯一的。这个“应该”促进了可互操作的输出,而不使唯一性成为基本对象语法的一部分。重复的名称仍然由有效的字符串、冒号和正确的逗号分隔位置的值组成。因此,语法验证器可以接受该文档,而应用程序策略则拒绝该文档。

这种区别很容易被忽略,因为许多错误都是强制语法错误:缺少冒号或尾随逗号根本无法形成 JSON 对象。重复的内容不同。在解析器识别出每个标记后,它们会创建一个互操作性问题。 ToolAcre 有意停止在语法上,并且不添加重名规则,因此其 Valid 结果不得被视为唯一性保证。

JSON.parse 和 ToolAcre 的作用

`JSON.parse` 使用稍后出现的位置。 ToolAcre 继承了该行为,因为它在格式化之前进行解析。对于 `{"limit":10,"limit":25,"unit":"items"}`,验证成功,解析的限制为 25,格式化输出包含一个 `limit`。可选的键排序可以重新定位幸存的属性,但不能暴露被覆盖的事件。

不要将该结果推广到每个解析器或配置。某些系统可以拒绝重复项,而其他处理堆栈可能会应用不同的策略或在构造对象之前检查令牌。安全的跨系统声明是狭窄的:重复的名称不能可靠地互操作。当区别很重要时,检查每个边界使用的实际解析器模式,而不是依赖于语言范围的声明。

当解析器分歧成为风险时

只有在组件以不同方式解释相同文本的具体多阶段路径中,重复才会成为安全问题。例如,请求过滤器可能会检查一次事件,而应用程序则使用另一次事件。这是否会发生取决于确切的解析器、选项、转发行为和字段使用。仅重复语法并不能证明是可利用的绕过方法。

可防御控制是在信任边界建立一项策略并测试真实堆栈。当歧义不可接受时,在有损对象构造之前拒绝重复名称,或者确保每个组件接收相同的已解析表示。 ToolAcre 可以演示其自己的最后胜利格式化行为,但它无法审核不属于浏览器工具的网关、框架或服务。

工作示例:具有重复键的文档

粘贴 `{"theme":"light","prefs":{"density":"roomy","density":"compact"},"theme":"dark"}`。 ToolAcre 接受文本,因为每个成员在语法上都是有效的。解析后,根主题为 `dark`,嵌套密度为 `compact`。格式化会发出每个名称的一份副本,因此两个较早的值都会从显示的文档中消失。

该示例还说明了为什么搜索格式化结果为时已晚。重复检测必须在读取每个对象深度的原始令牌流时观察成员名称。数组不需要重复名称规则,尽管单独的应用程序规则可能关心重复的元素值。保持源不变,对其运行重复感知解析器或 linter,并确定策略是警告还是拒绝。

故意检测重复项

使用明确承诺对源 JSON 进行重复名称检测的工具。合适的方法包括重复失败的解析器模式、跟踪每个打开对象名称的流令牌处理程序或具有记录的重复键规则的 linter。验证嵌套对象和转义名称: `"name"` 和 `"name"` 解码为相同的成员名称,即使它们的源拼写不同。

JSON 模式就不能替代。模式验证器通常接收构造的值并查看一个属性,而不是重复的令牌历史记录。在解析之前或解析期间运行唯一性检查,然后对明确的值应用架构检查。 ToolAcre 既不执行重复检测,也不执行架构验证,因此两者都需要单独的、专门构建的步骤。

这不包括什么

重复的对象名称与记录中的重复值不同。 `[ {"id":7}, {"id":7} ]` 包含两个独立的对象,每个对象都有一个 `id`;检测重复标识符有一个数据集规则。同样,具有相同字符串的两个数组元素保留两个有意位置,除非应用程序合约表明该数组代表一个集合。

本文并不主张针对广泛的语言生态系统采用普遍的先胜、后胜或拒绝政策。它记录了 ToolAcre 可观察到的 `JSON.parse` 行为,并解释了为什么必须直接检查另一个组件。它也不能单独确定副本的可利用性。安全影响需要证据证明不同的解释跨越相关的授权、路由或验证边界。

要点:有效的 JSON 并不总是明确的 JSON

ToolAcre 有效结果意味着令牌序列是严格的 JSON;这并不意味着每个对象名称都是唯一的。 `JSON.parse` 保留重复名称的最后一个值,并且格式化仅序列化该幸存者。由于较早出现的内容已被删除,因此格式化输出不适合作为确定原始源是否包含重复项的证据。

当唯一性很重要时,请在普通解析或格式化之前使用重复识别工具检查原始文本。随后对生成的明确值应用架构和域验证。为了进行安全审查,请跟踪实际的请求路径和解析器设置,而不是假设存在分歧。实际规则很简单:语法接受、重名策略和下游含义是使用单独证据的单独检查。