摘要

  • JSON Type Definition 判断实例是否符合一份刻意受限的结构契约;通过校验是关于形状的证据,不是关于事实或权力的证据。
  • 八种互斥形式、逐层生效的未知字段政策和双指针错误格式,通过拒绝诱人的歧义来换取可移植代码生成。
  • 生产治理从模式校验结束处开始:发送者身份、行为授权、领域不变量、重放、持久化与结果必须分别核验。

一条删除账户的事件到达系统。事件类型是字符串,账户编号存在,时间戳格式正确,没有多余字段。校验器返回空错误列表。此时最危险的一句话是:“这条消息有效,所以账户已经删除。”

RFC 8927 给“有效”划了一条精确边界。JSON Type Definition(JTD)能证明一个 JSON 实例与某份模式之间的结构关系:字段是否存在、整数是否落在范围内、标签是否选择了允许的分支。它不能证明账户真的存在,时钟可信,发送者有权删除,命令没有被重放,更不能证明存储层已经执行。

这种有限性不是缺陷,而是可移植性的来源。

小语言给出较清楚的承诺

RFC 8927 属于 Independent Stream,状态是 Experimental;它没有 IETF 共识,也不是 Standards Track。实验的问题很具体:如果模式语言的表达力不超过主流编程语言类型系统,独立实现是否更容易生成代码并给出一致的校验结果。

JTD 只有八种彼此互斥的形式。empty 接受任意实例;ref 引用根部定义;type 处理基础类型与时间戳;enum 限定非空且无重复的字符串集合;elements 约束数组元素;properties 描述记录;values 描述键值映射;discriminator 用字符串标签选择记录分支。

互斥消除了优先级争议。一个模式不能一半像记录、一半像标签联合,再让不同校验器自行决定先算哪条。分支也不能重新定义 discriminator 字段的类型。definitions 只允许出现在根模式,ref 因而不会随着嵌套位置变化而悄悄换义。

这正是“最小初始规范”的工程版本。共享层只承载各方能一致执行的部分;更丰富的政策可以存在,却不会因为写在旁边就自动成为共同规则。

空门也会亮绿灯

empty 形式是防止夸大校验意义的最好例子。它接受任何 JSON 值,而且永远不产生错误。于是,同样的“通过”既可能表示对象满足了几十项结构约束,也可能表示根本没有内容约束。没有模式哈希、版本与运行模式,绿色结果几乎无法复现。

metadata 的边界同样重要。JTD 允许元数据承载文档、代码生成提示或本地工具信息,但其他参与者不应被假定理解它。若某个元数据字段改变校验行为,只有各方在带外明确约定扩展后,它才具有共同语义。一个名叫 approvalRequired 的提示看起来很正式,也可能被合规校验器完全忽略。

因此,审计凭证必须把原始消息哈希、模式哈希、校验器版本与扩展配置绑在一起。只写“JTD 通过”没有说明究竟通过了哪一道门。

未知字段政策逐层作出

properties 形式把必填成员与可选成员分开,同一个名字不能同时属于两组。默认情况下,未声明成员会被拒绝;additionalProperties:true 可以开放这一层。

关键在“这一层”。根对象允许额外成员,并不会让嵌套对象自动继承。内层模式必须独立决定。这样,外部信封可以为未来路由信息保留扩展空间,而内部授权请求仍保持封闭。

若平台把未知字段当作一个全局开关,就会抹去这条风险边界。记录不应只写“宽松模式”,而应指出额外字段出现在哪个对象层级、由哪条规则接受或拒绝。

位置不是优先级

JTD 的标准错误对象包含两个 JSON Pointer。instancePath 指向输入中被拒绝的位置,schemaPath 指向作出拒绝的模式位置。这对复现很有价值:运营者能看到哪个值撞上了哪条规则。

但错误数组的顺序没有规定。第一项不一定是根因、最严重问题,也不代表时间上的第一次失败。若自动修复系统按数组位置排序处置,它就在规范之外创造了新的权力。JSON Pointer 只给出文档坐标,不给出业务归属,更不授权修改。

精确地址容易被误读为裁决。它只是证据的位置。

类型减少歧义,却不会消除现实歧义

JTD 提供有符号与无符号的 8、16、32 位整数,float32、float64、布尔、字符串和时间戳。对于整数,只要数学值在范围内,JSON 中的 10、10.0 或 1.0e1 都可被接受。时间戳则需符合 RFC 3339,并采用 RFC 4287 的收紧规则。

这能阻止明显的结构错误,却不能证明浮点测量准确、字符串对应真实客户,或时间来自可信时钟。一个格式完美的未来时间仍可通过;一条旧的、曾经获授权的命令被重放时,也可能完全符合模式。

JTD 没有提供 int64 和 uint64,反而体现了诚实。JSON 生态并不能一致保留完整 64 位整数精度。I-JSON 给出的可互操作整数范围更小。与其提供一个看似保证全范围的类型名称,规范选择不承诺。

扩展也应遵守同一原则:某个生成器能够输出,不等于所有接收者能够无损解释。

标签选择分支,不会让事件发生

discriminator 形式描述标签联合。对象必须含有指定标签;标签值必须是映射中的字符串;被选中的 properties 分支也必须通过。它可以阻止一条自称 account_deleted 的消息漏掉账户编号。

它无法证明删除确实发生。标签来自生产者。认证只能说明谁发送;授权决定他能否提出请求;审计记录证明系统是否接受;持久化与回读才接近结果。若把这些凭证压成一次模式通过,语法完整的声明就获得了制造现实的权力。

校验器本身也是攻击面

模式可以引用根定义,粗心的引用图可能形成循环。RFC 8927 建议处理用户输入模式的实现发现并中止循环,否则朴素校验器可能无限运行,成为拒绝服务目标。RFC 8259 还允许解析器限制输入长度、嵌套深度与数值精度。

所以,校验不是零成本谓词。运营策略需要字节、深度、引用展开、错误数量和执行时间预算;还要说明模式是受信构件、租户输入,还是远程依赖。一份语法正确的模式仍可能是一份恶意工作量。

实验要由运行证据回答

RFC 8927 对参与写得很清楚:节点只要校验 JTD 消息、依赖另一节点校验,或运行由 JTD 生成的代码,就在参与实验。成功标准是多个独立实现实际交换信息。RFC 的出版日期并不能替代这些事实。

这符合“运行代码优先”。RFC 编号、仓库徽章和模式文件只是符号潜力;模式哈希、独立校验结果、实际交换的消息与一致的错误位置才是运行证据。采用是自愿的,没有实现的节点不会因文档存在而自动执行规则。

来源

  1. RFC 8927:JSON Type Definition
  2. RFC 8259:JSON 数据交换格式
  3. RFC 7493:I-JSON 消息格式
  4. RFC 6901:JSON Pointer
  5. RFC 3339:互联网日期与时间
  6. RFC 4287:Atom Syndication Format
  7. RFC 8610:Concise Data Definition Language
  8. Heng Lu:Running-Code Primacy
  9. Heng Lu:Minimum Initial Specification, Localized Future Decision, and Voluntary Adoption
  10. Heng Lu:On Reality Layers, Symbolic Power, and Why Clarity Feels So Hostile