摘要

  • ZONEMD 把一个 SOA 序列号与按规范顺序排列的完整区域摘要绑定,glue 与被遮蔽数据也在覆盖范围内。因此,即使传输成功、版本号正确,它仍能识别内容不等于发布者承诺的副本。
  • 通过 DNSSEC 验证的摘要只是一张“可以启用”的内容收据,不是政策正确、所有节点已加载或业务正常的证明;运营者仍须保留验证、隔离、旧版回退和在网查询的完整证据链。

想象一次看似没有争议的区域更新。发布系统给出新的 SOA 序列号,辅助服务器完成 AXFR,写盘操作返回成功,解析器也没有遇到非法语法。监控平台看到目标序列号,便把更新标成完成。

真正的副本少了一条 glue RR。它仍是一份可解析的区域;SOA 也仍然写着预期数字。依赖那条地址跨越委托边界的查询,却可能在某些权威节点上失败。仅查看序列号,运营团队甚至会把故障节点误认为已经追平。

RFC 8976 定义的 ZONEMD 正是为了回答这类问题。区域顶点的 ZONEMD 记录携带对静态区域数据的消息摘要。接收方用同一套规范化规则重新排列并散列全部记录;本地结果如果不同,就不能把“传完了”或“版本对了”当成内容相同。

序列号是顺序,不是内容身份

RFC 1035 把 serial 放进 SOA,RFC 1982 则规定有限位宽下如何比较新旧,包括回绕时的次序。它们解决的是分布式副本何时应当尝试更新,而不是两份区域是否逐项相同。

发布者可能因构建分叉而给两份不同内容写入同一 serial;传输之后的文件、对象存储或恢复流程也可能改变内容却不改变 SOA。用一个数字与它自己比较,永远发现不了这种差异。

ZONEMD 没有取代 serial,而是在 RDATA 中再次写入对应的 SOA serial,再附上 Scheme、Hash Algorithm 与 Digest。两者形成互补:serial 说明发布者命名的版本,digest 说明这个版本所承诺的规范化整区内容。两项检查缺一不可。

这也与已有的 NOTIFY/IXFR 主题保持清楚边界。RFC 1995 规定增量传送,RFC 5936 规定完整区域传送。它们可以让副本更快收敛,却不会自动为传输后又经历仓库、落盘、重启和加载的整份对象留下一个可复算承诺。

摘要覆盖的是 DNS 语义,不是文本排版

ZONEMD 的 RR type 是 63。RFC 8976 当前标准化的 collation 方案是值为 1 的 SIMPLE,所有实现必须支持。Hash Algorithm 1 是必须支持的 SHA-384,完整摘要为 48 字节;算法 2 是建议支持的 SHA-512,完整摘要为 64 字节。分配状态由 IANA DNS 参数登记表维护。

SIMPLE 不是对某个 zone file 的原始字节直接做 hash。注释、空格、大小写和换行可能不同,却表达同样的 DNS 数据。记录先按 RFC 4034 的 DNSSEC 规范线格式与顺序处理;同一 owner 下的 RRset 还按 RR type 数值排序。由此得到的是对 DNS 内容的承诺,而非对编辑器输出风格的承诺。

纳入规则决定了这项机制为何有价值。区域内的记录原则上全部计入,glue 和 occluded data 也不例外;完全重复的 RR 只计一次;区域外数据不因与文件一起出现就被纳入。签名区域中的 DNSSEC 记录通常计入,但区域顶点的 ZONEMD placeholder 及最终覆盖 ZONEMD RRset 的 RRSIG 被排除,以避免摘要自我引用。

这与“DNSSEC 已经签了所有东西”的日常简化说法不同。DNSSEC 主要保护用于应答验证的 RRset;委托与 glue 的签名边界并不等于整份区域对象。ZONEMD 面向的是接收完整区域的系统,把这些对分发和引导同样关键的记录纳入一个整体承诺。它补充 DNSSEC,而不是替换 DNSSEC。

SIMPLE 的代价也来自“整体”二字:哪怕一条 RR 改变,也要重新遍历区域。RFC 8976 明确提醒,它适合较小或较稳定的区域,对大型、高动态区域可能不现实。评估不能只看软件是否出现一个开关,而要测摘要计算、签名、验证、传播、失败重放能否始终落在最短更新周期之内。

发布顺序本身就是控制面

签名区域不能先完成所有工作,再随手追加一条 ZONEMD。新增的顶点类型会影响 NSEC 或 NSEC3 的 type bitmap。规范要求先移除旧 ZONEMD 及其覆盖签名,再在 DNSSEC 签名前放入 placeholder,使不存在性证明从一开始就知道该类型存在。

签名之后,SIMPLE 对规范化记录流计算摘要,不纳入 placeholder,也不纳入之后才会生成的 ZONEMD 覆盖签名。摘要填回记录后,再生成或更新该 RRSIG。

这里有一个很容易破坏整条链的规则:为 ZONEMD 生成签名不得再次推动 SOA serial。最终 SOA 与匹配的 ZONEMD 必须同时发布。否则,用来认证承诺的动作反而改变了被承诺的版本。

因此,审计材料不能只保存查询结果中的一串十六进制字符。发布端至少要留下源快照、构建器与签名器版本、SOA serial、placeholder 阶段、方案与算法、最终 digest、DNSSEC 密钥上下文以及原子发布时间。没有这些字段,事故后无法判断错误来自源数据、构建、签名还是发布切换。

验证的第一步是确认“本来应该有什么安全性”

接收方不能看到 ZONEMD 就直接计算比较。它要先根据本地 trust anchor,必要时再根据父区中经过验证的 DS 链,判断该区域是否应当包含 DNSSEC。验证逻辑的基础来自 RFC 4035。

如果预期有签名,验证器必须确认 ZONEMD 是否应存在,并验证 SOA 与 ZONEMD 两个 RRset 的签名。DNSSEC 证明该记录不存在时,只能得出无法进行摘要验证;DNSSEC 证明它应存在、收到的副本中却没有,则绝不能判为成功。签名失败时,也不能因为本地 hash 偶然相等而悄悄降级成 checksum。

之后才是结构与内容检查。多个 ZONEMD RR 必须各自具有唯一的 scheme/hash 组合;本地策略可以拒绝某个组合。每条候选记录都要检查 SOA serial 精确相等、方案和算法受支持、摘要长度正确,再计算本地 digest。算法迁移期间,只要一个本地允许的组合匹配即可成功。

这项便利也带来降级风险:多算法并存时,整体安全性只到仍被接受的最弱算法。迁移流程必须写明旧组合何时删除;只会增加、不会退出的“兼容期”,最后会变成永久后门。

验证结果还应携带原因。记录缺失、信任链不可用、serial 不同、组合重复、算法不受支持、长度非法和内容 mismatch 分属不同故障域。把它们压成一个红灯,会让处置系统失去决定隔离、重试、回退或升级所需的信息。

没有 DNSSEC,攻击者可以连摘要一起改

未签名的 ZONEMD 仍有作用,但它的能力只能称为校验和。传输截断、磁盘损坏或无意修改发生后,只要原摘要保留,它就能发现差异。能够恶意改区的攻击者,也能重算 digest 并同时改写 ZONEMD,因此未签名模式不提供真正的抗攻击保护。

DNSSEC 让删除、替换承诺变得可检测,并把 SOA/ZONEMD RRset 认证到信任锚。但它认证的是“发布者确实承诺了这份内容”,不是“发布者的政策一定正确”。一个获授权但犯错的发布流程可以对错误委托生成完全有效的签名与摘要。匹配也不证明域名所有权、变更单合规、服务安全,或所有权威节点已经运行该版本。

传输认证也应保持独立。RFC 8945 定义 TSIG,以共享密钥保护 DNS transaction,常用于 AXFR/IXFR 对端身份和报文完整性。数据写盘、被重新打包、从备份恢复或在重启后加载时,旧 transaction MAC 并不会附着在整份对象上继续证明它未变。ZONEMD 承担的是跨越这些后续边界的内容校验。

拒绝错误区域,也可能拒绝服务

名称服务器可以在启用前验证 ZONEMD,并拒绝加载失败副本。这是最直接的完整性收益:错误内容没有机会成为权威答案。

同一动作会增加可用性脆弱性。发布器 bug、规范化实现差异、误删一条记录和蓄意篡改,在验证时可能表现为同一个 mismatch。严格阻断会让一部分本来正确的数据也随整区不可用;多个权威供应商如果采取不同策略,还可能在全球产生代际分裂。

RFC 8976 因此讨论渐进部署:先告警,积累经验后再转为错误。ICANN 的 RZERC003 建议把根区引入视为 Root Zone Maintainer、根服务器运营者、软件实现者和本地根用户之间的协调变更。其价值不在于提供一份可复制的统一策略,而在于提醒:一条摘要记录会改变多个独立故障域,强制执行前必须让责任人达成一致。

成熟系统至少要区分三种状态:候选版本验证通过,可以进入加载;候选失败,进入隔离,旧的已验证版本在有限时段内继续服务;证据不足,例如信任链故障而非内容差异,需要由明确授权者选择 fail-open 或 fail-closed。每种状态都必须有期限和升级负责人。

旧版也不能无限期充当避难所。继续服务已验证旧版可以保持内容完整性,却不断增加陈旧风险。允许多久取决于区域 refresh、expire 与业务影响。真正的 rollback 因而不是把指针改回去,而是证明旧对象仍存在、仍能独立验证、仍可加载,并能在权威应答中被观察到。

内容收据必须走到在网应答

一个 staging 主机验证成功,生产环境仍可能分裂。权威 DNS 可以由多个供应商和大量 anycast 实例共同提供,RFC 8901 讨论了多供应商环境。一次 reload 成功不等于进程已经服务新区域;从一个网络位置查询,也不代表其他 catchment 已收敛。

完整收据应串联五段。发布端把源快照、serial 与签名摘要绑定;传输或仓库记录对象身份、大小、本地 hash 与保管事件;验证端记录预期 DNSSEC 状态、trust anchor、允许组合、本地计算值与原因;启用端记录新旧 generation、隔离或批准和 fleet rollout;运行端再从规定范围查询 SOA、ZONEMD 以及若干真正纳入摘要的记录。

canary 不能只查 SOA,否则只是重复序列号盲点。应覆盖委托敏感名称、选定 glue 地址、签名 RRset 与负面应答,并保存具体权威身份和观察网络。按 RFC 8806 部署 hyperlocal root 的系统,还应为本地副本和刷新链建立独立收据,不能借用公共根服务器的运行状态。

关闭事故同样需要负面证据。回退或退役之后,被拒绝的 digest 与 generation 应从 staging eligibility、服务进程和抽样应答中消失。只证明正确版本在某处出现,不能排除遗漏节点仍在服务错误版本。

资料来源