摘要

  • RFC 9804 中,abc、"abc"、#616263#、3:abc 和 |YWJj| 可以表示同样三个八位组;只有规范表示给出用于签名计算的唯一字节序列。
  • 显示提示若存在,会进入被签名的规范对象,但其职能仍是展示建议,并不能证明类型安全、信任或授权。
  • 可审计系统应分别保存输入、解析器配置、规范输出、签名、类型解释、策略决定和实际结果的收据。

五种可读答案,只有一个字节问题

运维人员看到 abc,另一套控制台显示 "abc",归档里是 #616263#,协议跟踪写着 3:abc,诊断工具则输出 |YWJj|。RFC 9804 用这些例子说明:表面字符完全不同,却都能解析为同样三个八位组。

这种等价关系没有回答最关键的问题:哪一种表示跨过了签名边界?截图只能证明某个渲染器显示过什么;复制出的字符串只能证明复制了哪些字符;“解析成功”只证明某个实现接受了输入。数字签名的对象更窄——S-expression 的规范字节。

RFC 9804 把 S-expression 定义为八位组串或有限列表,并区分四个经常在事故记录中混为一谈的环境:高级表示供人输入和阅读;基本传输帮助规范对象通过不适合任意二进制或长行的通道;规范表示为签名提供唯一编码;内存表示则由实现自行决定。

规范表示给每个字符串加上十进制字节长度和冒号,随后逐字节输出;列表内部没有可选排版。完整规范表达式还可以做 Base64 编码后放入花括号。花括号形式只是运输包装,解码后必须回到同一组规范字节,不产生第二种被签名的含义。

高级表示允许标记、引号、十六进制、Base64、长度前缀和灵活空白,适合调试与界面,但支持它并非强制。应用只有在配置明确要求或能力协商确认后才应接收。收据若只写“S-expression 已接受”,就遗漏了所用记法、解析器版本、开启的语法、深度和长度限制,以及应用侧的额外约束。

显示建议不是类型权威

RFC 9804 允许八位组串附带显示提示。提示告诉应用如何展示数据,除此之外没有其他职能。提示存在时会写入规范表示,因此签名可以覆盖提示的存在与精确字节。

被签名不等于拥有语义主权。它只证明签名者放入了这段提示,不能证明接收方以安全方式解释了数据、提示中的媒体类型属实,或策略应当放行动作。缺少提示时,应用可以使用本地默认值;一般默认值是 application/octet-stream。两个渲染器对相同八位组给出不同画面并不矛盾。

相等规则也属于应用。RFC 9804 建议显示提示与数据都相同时才视为相等,但允许应用忽略提示或采用别的准则。因此审计必须记录比较规则及版本,否则“这是同一个 S-expression”仍然不完整。

语法只是第一道门

通用语法可以接纳消费协议必须拒绝的结构。RFC 9804 明确允许应用禁止提示或高级记法、拒绝空串和空列表、强制结构并设置资源上限。SPKI 就有具体收窄:RFC 2693 的证书用途不允许空列表,并要求列表第一项为类型字符串。

证据链应从原始输入字节和运输框架开始,记录解析器构建版本、启用语法、应用配置和资源限制,再保留解析所得的抽象对象。随后重新输出规范字节并计算哈希。签名验证必须点名这组字节以及所用密钥或证书路径,不能用任何界面渲染替代。

验证之后才是解释。RFC 2692 指出,SPKI 授权字段的含义由应用代码作者定义。RFC 2693 描述可信元组与授权归约,但最终许可仍取决于应用。收据要标明类型处理器、策略版本、主体、动作、资源和决策。只有执行记录才能说明系统尝试了什么以及实际发生了什么。

于是系统得到的是一条链,而不是万能的绿色勾号:

  1. 收到并解码运输字节;
  2. 指定语法和应用配置接受输入;
  3. 解析产生抽象表达式;
  4. 规范序列化产生有记录的字节哈希;
  5. 签名在该边界上验证通过;
  6. 指定处理器赋予含义;
  7. 有版本的策略返回授权结果;
  8. 执行产生可独立观察的结果。

链条允许定位分歧。两个解析器不一致,就比较输入和规范哈希;签名一致而结果不同,就检查类型与策略处理;授权为允许却没有变化,就追查执行。RFC 9804 让规范一致成为可能,却不会抹掉后续的权威边界。

来源