摘要

  • 9 月 12 日的快照显示,LACNIC 目录有 150 个反向 DNS 数据文件,分成 75 对对应名称,并列出 150 个分离式签名和一个公钥文件。
  • 抽查的一对文件字节完全相同,公布的 MD5 也与下载内容一致;这些证据能够描述单个文件,却没有列出一个完整发布批次应当包含什么。
  • 没有批次清单不等于文件缺失、签名失效或 DNS 故障。它只是让整目录镜像缺少一份可签名核验的“交付目录”。

打开 LACNIC 的公开目录,单个文件的验证路径很直观。002-LACNIC 旁边有同名的 .asc 签名和 .md5 校验值,目录根部还有 PUBLIC_KEY。如果使用者已经知道自己要取哪一个文件,这套摆放方式足够清楚。

问题出现在使用者想复制全部内容时。

冻结快照里有 150 个数据文件。其中 75 个采用三位数字名称,例如 002-LACNIC;另 75 个采用 2.in-addr.arpa-LACNIC 这种 DNS 名称。每一个三位数字名称都能找到数值对应项。目录同时列出 150 个 .asc 文件和 151 个 .md5 项;多出来的是索引里那个大小为零、名为 *-LACNIC.md5 的通配符项。

快照中没有文件名带有 README、manifest、SHA-256 索引、版本号或 release 标记。这只是对当时网页目录的准确描述,并不能反推 LACNIC 内部没有生成记录。

抽查证明了什么

样本对 002-LACNIC 和 2.in-addr.arpa-LACNIC 都是 2222 字节,SHA-256 完全相同。前一个文件公布的 MD5 也与实收字节相符。两个 HTTP 修改时间相差一秒。

最稳妥的结论很窄:在那个观察时点,这两个名称指向相同内容。它没有证明其余 74 对也相同,更没有证明所有名称永远都应相同。相差一秒也不构成发布不一致,完全可能只是两个兼容名称依次写入。

样本内容以 $ORIGIN . 开头,随后是 NS 委派行。它不是对线上权威服务器的查询记录,也不是完整权威区已被所有服务器加载的证明。下载文件、权威装载、递归解析器观察到的答案,是三个不同的证据表面。

签名封住文件,却不会自动封住文件夹

RFC 9580 所定义的分离式 OpenPGP 签名,可以对存放在签名对象之外的数据进行签名。只有在验证者接受相应公钥并实际执行验证时,它才可能把某个文件与某个签名者联系起来。

这次调查环境没有 OpenPGP 验证工具,因此没有宣称样本签名有效,也没有宣称它无效或公钥不可信。可以确认的是:LACNIC 已公开了建立单文件验证流程所需的签名材料。这是应当保留的控制,不是应被抹去的缺点。

但 002-LACNIC.asc 无法告诉镜像程序,和它同批的究竟还应有 149 个文件、49 个文件,还是没有别的文件。网页索引只能说明某一刻服务器列出了什么;HTTP 的 Last-Modified 也不是签名后的批次身份。

MD5 更不能代替这层证明。RFC 6151 指出,需要抗碰撞能力时不能再使用 MD5,但也承认它可以承担有限的传输差错检测。样本 MD5 相符,说明下载字节通过了这一项检查;它不验证发布者,也不枚举整批成员。

现有设计最有力的辩护

公开目录未必承诺提供原子快照。LACNIC 可能希望使用者按已知名称取回一个文件,各自缓存、各自更新。这样做简单、省带宽,也允许独立替换某个文件,而不用让所有使用者下载全部内容。

如果这就是产品边界,那么“逐文件”并没有错。只有当使用者把目录当作整批数据源时,缺口才出现:它无法用一份签名对象回答“我现在看到的是发布中途,还是已经完成的同一代文件”。

解决办法不需要新建庞大平台。每一代增加一份签名清单即可。清单应写明版本、批次 ID、生成时间、完成时间和按顺序排列的预期文件名;每一项再列出配对标识、名称角色、字节数、SHA-256 和签名文件名。

清单还应写入被接受的签名密钥指纹、上一批次、发布完成状态和更正入口。若后来发现要修正一个文件,就生成新版本,明确指向被替代的旧版本,而不是让旧状态静默消失。

这份清单不会声称 75 对文件必须相同。恰恰相反,它会给有意差异一个可解释的位置。它也不保证 DNS 线上服务正确,只证明 LACNIC 在某个时点宣布哪一组下载文件已经发布完毕。

一枚印章能回答一页纸是否被封存。目录清单要回答的,是哪些页共同组成这一本册子。

来源