delphij's Chaos

选择chaos这个词是因为~~实在很难找到一个更合适的词来形容这儿了……

17 Jun 2023

带 DNSSEC 的域名转移

DNSSEC 是一组针对 DNS 协议的扩展,其主要目的是为数据的权威性(或者说DNS数据确实来自于有权发布这些数据的人) 提供一套验证机制。DNSSEC并不改善私密性,所有的查询依然是明文的。

目前最新的 DNSSEC 最佳实践指南是 BCP 237 (RFC 9364)。 值得说明的是,如果没有特别的需要,使用 DNS 服务业者的 DNSSEC 实现可以避免踩很多的坑, 尽管这样一来安全方面就完全要仰赖这些业者了, 但对普通的域名所有这来说这些服务要比他们自己去架设和管理要可靠不少。 本文并不打算深入介绍 DNSSEC 及其部署,而只是关注于在进行域名转移时需要注意的问题, 以备我个人未来进行参考。

首先我们来大致复习一下 DNSSEC 的验证过程。域名系统可以理解为一个有不同层次的分布式数据库,以 example.net. 为例, 这里一共涉及了三层:

  1. . 即「根域」,从 2010 年 7 月起,根域就是签名的了。
  2. net.,这是一个顶级域名,大部分顶级域名目前支持 DNSSEC。
  3. example.net.,这是我们通常在域名注册服务提供商那里注册得到的域名。

每一层都有一个或多个密钥签署密钥(「KSK」),以及一个或多个域签署密钥(「ZSK」)。其中,KSK需要由上一层签名的 DS 记录来确认其有效性,这些DS记录会有由该级ZSK签名的RRSIG记录。类似地,本层的 ZSK 会由 KSK 签名, 并且 KSK 之间也会互相签名。

如此,通过上一层的 DS 记录,DNS解析器可以验证下一级域名的 KSK 有效性,并完成验证 DNS 记录的全部密码学操作。 根域因为没有上一层 DS 记录,因此根域的 KSK 必须提前安装到 DNS 解析器里面,人们为此设计了一套机制 (RFC 5011) 来更新 DNS 解析器中的这个根域 KSK,并且设计了另一套机制 (RFC 8145) 来帮助根域的运营者了解 DNS 解析器中的 KSK 更新状况,这是题外话。

由此,支持验证 DNSSEC 的 DNS 解析器就可以从根域一直捋到最终域名的记录, 并使用这一链条上的公钥去验证每一个记录的真实性。 值得注意的是,仅仅证明知道名字的记录存在是不够的, 如果我们只是简单地签名一条不包含记录内容的消息,例如「不存在」, 那么这条消息就可以被攻击者记录下来并在收到正常查询时直接将消息传给查询者, 而一些关键记录,例如 DS 记录如果被对方认为不存在的话, 其后果将是致命的。出于安全考虑,我们也不能把签名用的密钥交给提供DNS服务的服务器, 因为那样一来一旦这些服务器出现安全漏洞,则密钥也就随之外泄了。 一个比较简单的思路就是提供一些这样的记录:某某到某某之间的记录不存在, 并对这些消息进行签名,这就是 NSEC 和 NSEC3 (两者的区别是后者采用了 HMAC,从而让枚举存在的域名记录变得困难, 但两者的核心思路是类似的)。

有了以上这些以后,想要证明一个域是未经签名的就变成了让其上级域提供一条说明不存在 DS 记录的签名消息。 对于子域中大部分未进行签名的域来说,无论采用 NSEC 还是 NSEC3 都可能会产生大量的记录, 在 NSEC3 中提供了 Opt-out 机制 (RFC 5155 Section 6) 来避免这个问题。

有了这些准备知识,现在我们来考虑一下启用了 DNSSEC 的域名在转移注册商时可能会遇到的问题。 顶级域名都是签名了的,而注册商则会在这些域中添加和删除记录。这个过程中, 如果有一段时间存在 DS 记录与 DNS 服务器上的 KSK 不匹配的情况, 就会导致域名立即无法解析。

出于对人类的缺乏信心,目前绝大多数注册商都会要求用户首先禁用 DNSSEC,然后再转移域名。 此处值得注意的是,任何变动都需要推送到全球的上级域名镜像上,这个过程很快但依然需要时间, 而由于上级域名通常都采用了 anycast,因此并没有特别可靠的方法能够确保全球一致性。 因此,理论上在禁用 DNSSEC 之后,应等待原 DS 记录过期(至少其 TTL 时间) 之后才可以认为之前的数据已经没有人持有了。

实际情况中,除非管理员有什么大病,否则通常不会有人选择在更换域名注册商的同时来一次 KSK 轮转。 这种情况下并不需要真的等待24小时:即使禁用 DNSSEC 导致的 DS 记录删除没有反映到查询 DNS 的用户那里,他们也仍然可以从域名的 DNS 服务器获得经过签名的数据。而再次启用 DNSSEC 时, 由于使用的是同一组 KSK,因此其 DS 记录也是一样的。

但如果是在换域名注册服务提供商的同时更换了 DNS 服务器(例如,从旧的注册商提供的免费 DNS 服务器换到了新的注册商提供的对应服务上),除非可以同时迁移 key,否则最好是等待 DNSSEC 禁用满 24 小时(或TTL时间,请用 dig 域名 ds 确认)之后再启用 DNSSEC,此外, 在禁用 DNSSEC 之后、转移域名之前,最好也先等待一下,以免旧 DNS 在这个过程中停止服务导致的问题。

总结一下:

如果域名的 DNS 服务器仍然是原来那一组,检查清单是:

  1. 在转出的域名服务提供商那里删除域名的 DS 记录从而禁用 DNSSEC。
  2. 确认禁用 DNSSEC 生效(whois应该显示 unsigned 而不是 signedDelegation)。
  3. 正常发起域名转移,完成全部过程,确认 NS 记录正确转移到了新的服务提供商。
  4. 在新的域名服务提供商那里重新添加域名的 DS 记录从而启用 DNSSEC。
  5. 检验 DNSSEC 签名链。

如果域名的 DNS 服务器将换成一组新的,检查清单是:

  1. dig 域名 ds 获得目前的 DS 记录有效期时间。
  2. 在转出的域名服务提供商那里删除域名的 DS 记录从而禁用 DNSSEC。开始计时。
  3. 在新的域名服务提供商那里先设置 DNS,但不要启用。
  4. 等待第二步时间到达 TTL 时间,发起正常的域名转移同时启用新的 DNS。
  5. 确认 DNS 正确解析之后启用 DNSSEC。
  6. 检验 DNSSEC 签名链。