摘要

  • RFC 9839 给出三个由宽到严、可以被规范精确引用的子集:Unicode Scalars、XML Characters 和 Unicode Assignables。
  • 合法 JSON 可以通过转义承载控制码、孤立代理码点与非字符;解析成功并不证明解码结果可被良好 UTF-8 序列化,也不证明字段应当接纳它。
  • 真正的运营控制是:每个字段声明子集,明确拒绝或替换,并让入口、存储、日志、导出与消费端对同一组测试向量给出一致结果。

最危险的输入不一定触发红灯。网关返回成功,JSON 库生成对象,模式校验也可能通过。直到字符串进入另一种编程语言、写入数据库或重新编码为 UTF-8,孤立的代理码点才暴露出来。此时系统才发现:它证明的是“包裹能拆开”,不是“内容能获准进入”。

RFC 9839 于 2025 年 8 月以 Standards Track 发布。正式记录、纯文本与XML 源文档共同定义三个可复用边界。标准的存在不等于任何产品已经部署,也不等于历史数据已经合规。

“支持 Unicode”不是一个足够精确的开关

Unicode 码空间有 1,114,112 个码点,但码点是数字位置,不保证它代表适合开放交换的字符。Unicode Scalars 排除 U+D800 至 U+DFFF 的 2,048 个代理码点,却保留传统控制码和非字符。XML Characters 进一步排除大部分 C0 控制码以及 U+FFFE、U+FFFF,但仍保留 C1 控制码和更高平面的部分非字符。Unicode Assignables 则排除代理码点、传统控制码和全部非字符,同时允许已经分配或未来可能分配的码点。

Unicode 标准定义码空间,UAX 44说明字符属性;RFC 3629定义 UTF-8,RFC 2277确立互联网协议使用 UTF-8 的政策。编码解决“允许的值怎样变成字节”,并不替某个账户标识、签名声明或展示字段决定“允许哪些值”。

RFC 9839 用 ABNF描述边界,使规范不必把“有效 Unicode”的解释权散落给不同实现。XML 1.0的字符产生式是一个既有配置,不是所有文本安全问题的代名词。

转义只改变写法,不产生权限

RFC 8259及其状态记录定义 JSON。RFC 9839 展示了一段符合 JSON 语法的文本;解码后却含有 NUL、一个 C1 控制码、一个孤立代理码点与一个非字符。该值不能被序列化为良好 UTF-8,各语言库的处理还可能不同。

把禁用码点写成转义序列,并未改变它解码后的身份。子集检查必须发生在转义解析之后、权威状态写入之前。通用解析器懂引号和反斜杠,却不知道字段将用于人类展示、访问控制、哈希、签名还是法律证据。

I-JSON、Net-Unicode与 PRECIS说明不同用途需要不同配置。Unicode Assignables 也不解决规范等价、混合文字、双向显示、形似字符或上下文合法性;面向人的标识往往需要更严格规则。

拒绝与替换保存的是不同资产

拒绝可以阻止歧义值成为权威数据。替换为 U+FFFD 可以让展示链继续工作,并把损坏显示出来,但它会丢失精确身份。签名、内容哈希、去重键、权限比较或法律记录不能在替换后假装原文仍被保存。

静默删除尤其危险:两条原本不同的字符串可能被合并,审计记录也不再对应收到的值。RFC 9413所说的健壮性,是对无效输入给出有意识、可预测的处理,而不是无限度接纳。

拒绝也会形成可用性表面。若错误诊断昂贵,攻击者可反复投递异常字符串。速率限制、有限错误信息、隔离区和原始证据保留属于运营者的本地决定,RFC 不会替它完成。

运行链上的一致结果才是凭证

同一批向量必须穿过边缘网关、解析器、模式校验、消息队列、数据库驱动、持久化、日志、导出与下游消费者。语法失败、子集违规、主动替换和后续序列化失败要分别计数。对比的不是一句“通过”,而是解码标量序列、决策、错误类别与实际存储值。

CBOR的文本字符串默认采用 Unicode 标量值,因此排除了代理码点,却没有排除全部控制码与非字符。换封装格式只移动了一道边界,没有替代字段政策。

TR36讨论更广泛的 Unicode 安全,TR55聚焦源代码,W3C 则区分字符、码点、码元与字节。这些材料也标出 RFC 9839 的证据边界:它解决最低限度的开放交换问题,不包办所有人类可读安全。

本文没有测试任何厂商、运行时、数据库或生产链,也没有推断采用率。能够成立的结论更窄:格式解析器是语法协调者,不是内容授权者。只有运行中的各节点都能给出一致、可审计的准入结果,协议才真正完成了第二道门。

来源