带 DNSSEC 的域名转移
DNSSEC 是一组针对DNS协议的扩展,其主要目的是为数据的权威性(或者说DNS数据确实来自于有权发布这些数据的人)提供一套验证机制。DNSSEC并不改善私密性,所有的查询依然是明文的。
目前最新的DNSSEC最佳实践指南是BCP 237 (RFC 9364)。值得说明的是,如果没有特别的需要,使用DNS服务业者的DNSSEC实现可以避免踩很多的坑,尽管这样一来安全方面就完全要仰赖这些业者了,但对普通的域名所有这来说这些服务要比他们自己去架设和管理要可靠不少。本文并不打算深入介绍DNSSEC及其部署,而只是关注于在进行域名转移时需要注意的问题,以备我个人未来进行参考。
首先我们来大致复习一下DNSSEC的验证过程。域名系统可以理解为一个有不同层次的分布式数据库,以 example.net. 为例,这里一共涉及了三层:
.即「根域」,从2010年7月起,根域就是签名的了。net.,这是一个顶级域名,大部分顶级域名目前支持DNSSEC。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服务器仍然是原来那一组,检查清单是:
- 在转出的域名服务提供商那里删除域名的DS记录从而禁用DNSSEC。
- 确认禁用DNSSEC生效(whois应该显示unsigned而不是signedDelegation)。
- 正常发起域名转移,完成全部过程,确认NS记录正确转移到了新的服务提供商。
- 在新的域名服务提供商那里重新添加域名的DS记录从而启用DNSSEC。
- 检验DNSSEC签名链。
如果域名的DNS服务器将换成一组新的,检查清单是:
- 用
dig域名ds获得目前的DS记录有效期时间。 - 在转出的域名服务提供商那里删除域名的DS记录从而禁用DNSSEC。开始计时。
- 在新的域名服务提供商那里先设置DNS,但不要启用。
- 等待第二步时间到达TTL时间,发起正常的域名转移同时启用新的DNS。
- 确认DNS正确解析之后启用DNSSEC。
- 检验DNSSEC签名链。