type
status
date
slug
summary
tags
category
icon
password
什么是DNSSEC
DNSSEC(Domain Name System Security Extensions)中文名称为DNS安全扩展,它是由IETF提供的一系列DNS安全认证机制,通过向现有DNS记录添加加密签名,解析器可以验证来自于权威域名服务器请求的信息,从而保证域名系统的安全性。

发起一次域名查询的流程如上图所示,客户端需要访问www.baidu.com,会通过域名解析服务器发起递归查询,我们经常配置的114.114.114.114就是一个递归服务器。如果递归服务器存在记录缓存,那么就会直接将www.baidu.com的A记录直接返回给客户端;如果不存在就需要通过根服务器、顶级域名服务器、权威服务器、二级域名服务器迭代查询。
由于DNS解析使用的是UDP协议,UDP 是一种无连接的、不可靠的传输层协议,所以攻击者就能很容易通过假冒域名服务器(根、顶级、权威服务器)给客户端发送伪造的响应,响应的IP可能是无效地址或者是欺诈网站地址,从而达到网络钓鱼、提供非法广告、监控 Web 流量以及阻止对特定域的访问等。同时由于解析服务器有缓存的功能,这些记录就会在服务器中保存一段时间才会失效,这就是常见的DNS欺骗攻击和缓存污染。
DNSSEC设计目的就是为了解决DNS欺骗攻击和缓存污染,它使用数字签名技术保证DNS的真实性和完整性,这些数字签名会与A、CNAME等常见记录类型一起存储在DNS域名服务器中。解析服务器可以对响应进行校验来确保所请求的DNS记录是否来自权威服务器,并且没有被篡改或者注入虚假的信息。
DNSEC是如何设计和运行
为了保证签名、分发、验签整个过程的可信可靠,DNSSEC添加了新的DNS记录类型:
- RRSIG:用于存放资源记录签名
- DNSKEY:用于存放公共签名密钥
- DS: 用于存放公钥哈希
- NSEC、NSEC3:用于表示DNS记录不存在
RRset
RRset是一组资源记录集合,这个集合包含相同类型的记录。例如区记录里面存在www.baidu.com的多个A记录,那么它们就会全部归到一个A RRset中去。

ZSK
DNSSEC针对每一个区都有一对签名密钥ZSK(Zone Signature Key),ZSK的私钥用来对RRset进行数字签名,公钥用于验证签名,并将其哈希添加到DNSKEY记录中,方便递归服务器来查询。

递归服务器为了校验响应结果是否可信,他需要获取RRset、RRSIG和DNSKEY一同进行验证,使用DNSKEY对RRSIG进行解密,然后再与RRset哈希进行对比。如果DNSKEY是被信任的,那么如果验证通过,所有的记录就是可信任的。但是,DNSKEY泄漏或者被伪装那么还是不能保证数据的可靠,所以还需要有一种机制来验证ZSK是否正确可靠(套娃开始🪆)。
KSK
KSK(Key Signature Key)用来对ZSK进行签名和验证,使用KSK的私钥对ZSK公钥的DNSKEY记录进行签名,得到的数字签名也是一个RRSIG记录,为了能够对该RRSIG进行验签,将KSK的公钥存在在另一个DNSKEY记录中。此时就产生了两个DNSKEY,分别是:
- ZSK的DNSKEY:用于存放ZSK公钥和使用KSK进行签名的RRSIG记录
- KSK的DNSKEY:用于存放KSK公钥

此时,验证流程变得复杂起来,在ZSK流程的基础上,解析服务器向域名服务器请求ZSK公钥,返回了ZSK公钥的DNSKEY记录和对应的RRSIG记录(使用KSK签名的),为了校验ZSK的DNSKEY记录是否正确,解析服务器又需要向域名服务器请求KSK公钥,返回了KSK公钥的DNSKEY记录就可以验证ZSK的DNSKEY是否可被信任了。那么问题又来了,又该如何确保KSK的有效性呢?不会再设计出个KKSK来吧?
DS
为了验证KSK公钥的有效性,DNSSEC添加DS记录,该记录包含KSK公钥的DNSKEY的哈希,并由父区保存

于是整个校验过程又多了一步,解析服务器通过权威服务器B获取了KSK和ZSK后,还需要向他的父区顶级域名服务器A获取DS的记录,通过对比DS记录和KSK的哈希值来判断记录数据的有效可靠。这种设计使得子区的信任需要由父区来保证,父区的信任也需要由更上级保证,这样也就形成了一个完整的信任链。
信任链

每个区都有父区进行签名背书,如果信任父区,则子区所有记录在验证正确的情况就可以认定为是可信可靠的。根区的签名则是在“根区签名仪式”,由来自世界各地的特定的几人已公开且经严格审核的方式签署根DNSKEY RRset,并产生一条RRSIG记录,该记录用于校验根域名服务器的公共KSK和ZSK。
DNSSEC配置实践
配置
权威服务器A配置
- 首先创建一个
aaa.com的区,然后再添加一条www.aaa.com的A记录。
- 得到区记录文件aaa.com.txt:
- 使用dnssec-keygen生成该区的KSK
dnssec-keygen -f KSK -a RSASHA1 -b 512 -n ZONE aaa.com.- 使用dnssec-keygen生成该区的ZSK
dnssec-keygen -a RSASHA1 -b 512 -n ZONE aaa.com.- 生成两对公私钥对
- Kaaa.com.+005+29191.key Kaaa.com.+005+29191.private
- Kaaa.com.+005+50076.key Kaaa.com.+005+50076.private
- 编辑aaa.com.txt文件,将KSK和ZSK的key添加进去
- 对区记录进行签名,得到aaa.com.txt.signed文件
dnssec-signzone -o aaa.com. aaa.com.txt- 使用aaa.com.txt.signed替换aaa.com.txt,重启Bind
权威服务器B配置
- 创建一个
com的区,然后再添加一条aaa.com的NS记录。
- 得到区记录文件com.txt:
- 使用dnssec-keygen生成该区的KSK
dnssec-keygen -f KSK -a RSASHA1 -b 512 -n ZONE com.- 使用dnssec-keygen生成该区的ZSK
dnssec-keygen -a RSASHA1 -b 512 -n ZONE com.- 生成两对公私钥对
- Kaaa.com.+005+29191.key Kaaa.com.+005+29191.private
- Kaaa.com.+005+50076.key Kaaa.com.+005+50076.private
- 编辑aaa.com.txt文件,将KSK和ZSK的key添加进去,并将授权的子区aaa.com.的DS记录添加进来
- 对区记录进行签名,得到com.txt.signed文件
dnssec-signzone -o com. com.txt- 使用com.txt.signed替换com.txt,重启Bind
递归服务器验证
将递归服务器的根区指向权威服务器A
- 使用dig命令:
dig @递归服务器 www.aaa.com. +dnssec
- 如果配置的没有问题返回结果为:
- 进行抓包得到
- 递归服务器向112这台权威服务器请求
www.aaa.com.,112权威服务器返回aaa.com.的子域所指的服务器给递归服务器,假定为113权威服务器。 - 递归服务器收到后又向113权威服务器请求
www.aaa.com.,113权威服务器的区里有DNS记录并同时还会返回对应的RRSig(数字签名) - 递归服务器收到结果,需要根据RRSig来判断这条DNS响应是否是113这台权威服务器发出的,这时递归服务器就会向113权威服务器请求ZSK公钥
- 113权威服务器收到请求后就会返回ZSK、KSK的DNSKEY记录及对应的RRSig
- 递归服务器收到包含KSK公钥的DNSKEY记录后,向112权威服务器查询DS记录
- 递归服务器收到DS记录后,就可以对KSK公钥进行哈希,比较两个值是否匹配。
分析
由于整个过程是从根出发的,所以为了不从根再获取DS,就可以配置信任锚,将com.的DNSKEY添加到递归服务器里,这样就不会再根服务器去请求了。
在递归服务器的配置里添加Trust Anchors , 需要填写的就是com. 的DNSKEY 的记录值
总结
DNSSEC在并不安全的协议之上,添加了一个身份验证的安全层来确保记录的可信防篡改,类似HTTPS。通过使用DNSSEC,借助可靠的信任链就能有效地解决DNS欺骗攻击,防止攻击者给DNS系统带来潜在的安全威胁。
参考
- 作者:Ryan Wu
- 链接:https://hexo.fridaylab.top/article/4138273b-8177-4d6f-ac9c-951a584340b1
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
