摘要

  • RFC 8259 只要求对象名称“应该”唯一,却明确指出名称重复时,各实现可能保留最后一组、直接报错,或把所有值都交给调用者。
  • 解析器一旦把多个成员压成普通映射,后续的模式校验、日志重写和规范化只能整理幸存结果,无法找回已经丢弃的成员。
  • 可靠的控制点应位于语义使用之前:保留原始证据,在处理转义后比较名称,发现碰撞就拒绝,并把任何协议特例限制在明确范围内。

干净的对象可能来自不干净的选择

在线路上,JSON 对象是一串依次到达的名称和值。在应用内,它通常会变成键只能出现一次的映射。名称都不重复时,这两种表示似乎没有区别;重复一旦出现,转换就必须决定留第一个、留最后一个、保留全部,还是失败。

做决定的往往不是业务代码。API 网关可能先读正文,框架中间件随后构造对象,授权模块取出一个字段,审计组件再把对象序列化。若这些环节采用不同的碰撞规则,它们都可以声称解析成功,却没有处理同一组主张。

因此,“JSON 能解析”不是“JSON 只有一种含义”的同义词。前者只说明某个解析器给出了某个结果。

RFC 8259 留下的宽度

RFC 8259 对措辞十分克制:对象中的名称 SHOULD 唯一,也就是“应该”唯一,而不是基础语法层面的绝对禁止。含有重复名称的文本并不必然因为这一点就不再属于 JSON 语法。

但它对后果毫不含糊。名称唯一时,接收方会对名称和值的对应关系取得一致;名称不唯一时,软件行为不可预测。许多实现只报告最后一组,有些报错或解析失败,也有些把包括重复项在内的全部成员交出来。库是否向调用者暴露成员顺序,也存在差异。

这不是无关痛痒的兼容性注脚。假设前置控制读取第一次出现的权限,执行服务保留最后一次,而日志只记录压缩后的对象,最终档案内部完全自洽,却无法显示早期决策依据。问题不需要依赖某个真实事故才能成立:组件从一开始就没有共享同一个数据模型。

I-JSON 把建议变成入场条件

RFC 7493 为 I-JSON 设定了更窄的可接受范围:对象 MUST NOT 含有名称重复的成员。这里的“重复”要在转义字符处理完以后判断。正文中外观看似不同的两种写法,解码后可能成为同一个 Unicode 字符序列。

所以,仅在原始文本里查找相同字面片段并不足够。检查器必须看到每一个解码后的名称,同时不能让普通映射提前吞掉重复项。I-JSON 允许接收方拒绝或忽略不符合要求的消息,安全协议也可以要求不信任这类输入。

执行次序决定控制是否真实存在。如果重复检查拿到的是已经执行“最后值胜出”的映射,它必然找不到重复。检查必须使用能够报告重复名称的解析模式,或在构造映射之前,于词法、令牌或流式阶段观察所有成员。

第一层解析器拥有事实裁决权

没有显式策略时,库的默认行为就会选择哪一个值进入定价、路由、授权或持久化。一个为了方便而设计的数据结构,由此获得了未被承认的政策权力。

更稳健的入口会把这项权力交给明确责任人。它先限制正文大小和嵌套深度,以一致规则解码名称,在转义处理后发现碰撞,并在任何业务副作用之前拒绝。它还会按隐私与留存政策,另行保存接收字节或其密码学摘要,让调查者区分“实际到达的内容”和“解析器整理后的对象”。

把映射重新序列化不能替代原始证据。新文本证明的是解析器留下了什么,不一定证明系统收到了什么。

JWS 的局部规则不能外推

RFC 7515 对 JOSE Header Parameter 给出明确规则:参数名称必须唯一;JWS 解析器必须拒绝重复名称,或采用只返回词法顺序中最后一个重复成员的 JSON 解析器。

这是一条有边界的协议规则,不是“所有 JSON 都以最后值为准”的宣言。它针对 JOSE 头部参数,不自动覆盖任意 API 正文、配置对象或 JWS 载荷。JWS 签名验证回答受保护字节与密钥是否满足密码学关系,也不会单独决定应用是否应该执行其中表达的操作。

即便规范允许某种兼容路径,网关、验证器、业务服务和观测系统也必须在同一边界执行同一规则。否则,一个局部特例仍会产生多套事实。

规范化只能固定尚未丢失的内容

RFC 8785 的 JCS 为 JSON 生成确定性表示。它的前提顺序十分关键:输入要适配 I-JSON,对象不得出现重复属性名,基本值按规定序列化,属性再按确定规则排序。

换言之,JCS 不是先接纳歧义、再替系统决定谁胜出。它之所以能给出稳定字节,是因为进入规范化的数据模型已经没有重复名称。如果通用解析器先删去一个成员,JCS 再处理幸存映射,结果当然可以稳定;但它稳定的是那次有损投影,不能证明原始输入只有一个该名称,也不能恢复另一项。

在签名应用中,RFC 8785 还给出分层次序:解析并确认 I-JSON 合规,验证生态自身的约定,之后验证签名;任一步失败都要终止。语法可接纳、业务正确和密码学有效从而保持为三道不同问题。

对整条路径做一致性测试

工程契约应给每种表示命名:接收字节、解码令牌流、无重复且获准进入的对象、通过业务校验的领域模型,以及需要时的规范化形式或签名封装。每次转换都要有负责人、失败结果和证据去向。

测试样本应覆盖不同嵌套层级,还要加入只有在转义处理后才同名的成员。样本必须穿过真实网关、中间件、签名路径和日志系统,而不只是调用一个工具函数。合格结果不止是返回错误码:下游没有发生副作用,拒绝原因被正确分类,保留摘要仍对应原始正文。

解析库、运行时、网关或序列化组件升级时,都应重新运行这些跨组件样本。业务模式没有变化,并不代表碰撞语义也没有变化。

来源