如何在权威BINDDNS服务器上设置DNSSEC
关于 DNSSEC
我们都知道DNS是一种将域名解析为IP地址的协议,但是我们怎么知道返回的IP地址的真实性呢? 攻击者有可能篡改 DNS 响应或 毒化 DNS 缓存 并将用户带到地址栏中具有合法域名的恶意站点。 DNS 安全扩展 (DNSSEC) 是旨在维护 DNS 响应的数据完整性的规范。 DNSSEC 使用 PKI(公钥基础设施)对区域的所有 DNS 资源记录(A、MX、CNAME 等)进行签名。 现在启用 DNSSEC 的 DNS 解析器(如 Google 公共 DNS)可以使用公共 DNSKEY 记录验证 DNS 回复(包含 IP 地址)的真实性。
DNSSEC 资源记录
资源记录 (RR) 包含有关域的特定信息。 一些常见的有包含域 IP 地址的 A 记录、包含 IPv6 信息的 AAAA 记录和具有域邮件服务器的 MX 记录。 可以在 此处 找到 DNS RR 的完整列表。
同样,DNSSEC 也需要多个 RR。
- DNSKEY 保存解析器用来验证的公钥。
- RRSIG 存在于每个 RR 并包含记录的数字签名。
- DS - 委托签名者 - 此记录存在于 TLD 的名称服务器中。 因此,如果 example.com 是您的域名,则 TLD 为“com”,其名称服务器为
a.gtld-servers.net.
、b.gtld-servers.net.
到m.gtld-servers.net.
。 此记录的目的是验证 DNSKEY 本身的真实性。
设置环境
域名: 例子.com
我使用了一个真正的 .COM 域来执行此操作,但在本文中已将其替换为 example.com。
主域名服务器: IP地址: 1.1.1.1 主机名: master.example.com 操作系统: Debian 7
从名称服务器: IP地址: 2.2.2.2 主机名: slave.example.com 操作系统: CentOS
文件位置和名称
BIND 的配置文件和区域文件的名称和位置根据使用的 Linux 发行版而有所不同。
Debian/Ubuntu
服务名称:bind9 主配置文件:/etc/bind/named.conf.options
区域名称文件:/etc/bind/named.conf.local
默认区域文件位置:/var/cache/bind/
CentOS/Fedora
服务名称:named 主要配置和区域名称文件:/etc/named.conf
默认区域文件位置:/var/named/
如果您使用 bind-chroot
,这些可能会改变。 在本教程中,我将 Debian 用于 Master NS,将 CentOS 用于 Slave NS,因此请根据您的发行版进行更改。
DNSSEC 主配置
通过在 options{ }
中添加以下配置指令来启用 DNSSEC
nano /etc/bind/named.conf.options
dnssec-enable yes; dnssec-validation yes; dnssec-lookaside auto;
这些可能已经添加到某些发行版中。 导航到您的区域文件的位置。
cd /var/cache/bind
使用以下命令创建区域签名密钥 (ZSK)。
dnssec-keygen -a NSEC3RSASHA1 -b 2048 -n ZONE example.com
如果你已经安装了haveged,生成这个key只需要几秒钟; 否则需要很长时间。 样本输出。
root@master:/var/cache/bind# dnssec-keygen -a NSEC3RSASHA1 -b 2048 -n ZONE example.com Generating key pair..................+++ .............+++ Kexample.com.+007+40400
使用以下命令创建密钥签名密钥 (KSK)。
dnssec-keygen -f KSK -a NSEC3RSASHA1 -b 4096 -n ZONE example.com
样本输出。
root@master:/var/cache/bind# dnssec-keygen -f KSK -a NSEC3RSASHA1 -b 4096 -n ZONE example.com Generating key pair......................++ .............................................................................................................................................................................................................++ Kexample.com.+007+62910
该目录现在将有 4 个密钥 - ZSK 和 KSK 的私有/公共对。 我们必须将包含 DNSKEY 记录的公钥添加到区域文件中。 下面的 for
循环将执行此操作。
for key in `ls Kexample.com*.key` do echo "\$INCLUDE $key">> example.com.zone done
使用 dnssec-signzone
命令对区域进行签名。
dnssec-signzone -3 <salt> -A -N INCREMENT -o <zonename> -t <zonefilename>
用随机的东西代替盐。 这是一个输出示例。
root@master:/var/cache/bind# dnssec-signzone -A -3 $(head -c 1000 /dev/random | sha1sum | cut -b 1-16) -N INCREMENT -o example.com -t example.com.zone Verifying the zone using the following algorithms: NSEC3RSASHA1. Zone signing complete: Algorithm: NSEC3RSASHA1: KSKs: 1 active, 0 stand-by, 0 revoked ZSKs: 1 active, 0 stand-by, 0 revoked example.com.zone.signed Signatures generated: 14 Signatures retained: 0 Signatures dropped: 0 Signatures successfully verified: 0 Signatures unsuccessfully verified: 0 Signing time in seconds: 0.046 Signatures per second: 298.310 Runtime in seconds: 0.056
必须输入 16 个字符的字符串作为“salt”。 以下命令
head -c 1000 /dev/random | sha1sum | cut -b 1-16
输出一个 16 个字符的随机字符串,将用作盐。
这将创建一个名为 example.com.zone.signed
的新文件,其中包含每个 DNS 记录的 RRSIG 记录。 我们必须告诉 BIND 加载这个“签名”区域。
nano /etc/bind/named.conf.local
更改 zone { }
部分内的 file
选项。
zone "example.com" IN { type master; file "example.com.zone.signed"; allow-transfer { 2.2.2.2; }; allow-update { none; }; };
保存此文件并重新加载绑定
service bind9 reload
检查是否在同一台服务器上使用 dig
的 DNSKEY 记录。
dig DNSKEY example.com. @localhost +multiline
样本输出
root@master:/var/cache/bind# dig DNSKEY example.com. @localhost +multiline ;; Truncated, retrying in TCP mode. ; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> DNSKEY example.com. @localhost +multiline ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 43986 ;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0 ;; WARNING: recursion requested but not available ;; QUESTION SECTION: ;example.com. IN DNSKEY ;; ANSWER SECTION: example.com. 86400 IN DNSKEY 256 3 7 ( AwEAActPMYurNEyhUgHjPctbLCI1VuSj3xcjI8QFTpdM 8k3cYrfwB/WlNKjnnjt98nPmHv6frnuvs2LKIvvGzz++ kVwVc8uMLVyLOxVeKhygDurFQpLNNdPumuc2MMRvV9me fPrdKWtEEtOxq6Pce3DW2qRLjyE1n1oEq44gixn6hjgo sG2FzV4fTQdxdYCzlYjsaZwy0Kww4HpIaozGNjoDQVI/ f3JtLpE1MYEb9DiUVMjkwVR5yH2UhJwZH6VVvDOZg6u6 YPOSUDVvyofCGcICLqUOG+qITYVucyIWgZtHZUb49dpG aJTAdVKlOTbYV9sbmHNuMuGt+1/rc+StsjTPTHU= ) ; key id = 40400 example.com. 86400 IN DNSKEY 257 3 7 ( AwEAAa2BE0dAvMs0pe2f+D6HaCyiFSHw47BA82YGs7Sj qSqH3MprNra9/4S0aV6SSqHM3iYZt5NRQNTNTRzkE18e 3j9AGV8JA+xbEow74n0eu33phoxq7rOpd/N1GpCrxUsG kK4PDkm+R0hhfufe1ZOSoiZUV7y8OVGFB+cmaVb7sYqB RxeWPi1Z6Fj1/5oKwB6Zqbs7s7pmxl/GcjTvdQkMFtOQ AFGqaaSxVrisjq7H3nUj4hJIJ+SStZ59qfW3rO7+Eqgo 1aDYaz+jFHZ+nTc/os4Z51eMWsZPYRnPRJG2EjJmkBrJ huZ9x0qnjEjUPAcUgMVqTo3hkRv0D24I10LAVQLETuw/ QOuWMG1VjybzLbXi5YScwcBDAgtEpsQA9o7u6VC00DGh +2+4RmgrQ7mQ5A9MwhglVPaNXKuI6sEGlWripgTwm425 JFv2tGHROS55Hxx06A416MtxBpSEaPMYUs6jSIyf9cjB BMV24OjkCxdz29zi+OyUyHwirW51BFSaOQuzaRiOsovM NSEgKWLwzwsQ5cVJBEMw89c2V0sHa4yuI5rr79msRgZT KCD7wa1Hyp7s/r+ylHhjpqrZwViOPU7tAGZ3IkkJ2SMI e/h+FGiwXXhr769EHbVE/PqvdbpcsgsDqFu0K2oqY70u SxnsLB8uVKYlzjG+UIoQzefBluQl ) ; key id = 62910 ;; Query time: 0 msec ;; SERVER: 127.0.0.1#53(127.0.0.1) ;; WHEN: Wed Nov 27 18:18:30 2013 ;; MSG SIZE rcvd: 839
检查是否存在 RRSIG 记录。
dig A example.com. @localhost +noadditional +dnssec +multiline ; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> A example.com. @localhost +noadditional +dnssec +multiline ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32902 ;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 3, ADDITIONAL: 5 ;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags: do; udp: 4096 ;; QUESTION SECTION: ;example.com. IN A ;; ANSWER SECTION: example.com. 86400 IN A 93.184.216.119 example.com. 86400 IN RRSIG A 7 2 86400 20131227171405 ( 20131127171405 40400 example.com. JCoL8L7As1a8CXnx1W62O94eQl6zvVQ3prtNK7BWIW9O lir/4V+a6c+0tbt4z4lhgmb0sb+qdvqRnlI7CydaSZDb hlrJA93fHqFqNXw084YD1gWC+M8m3ewbobiZgBUh5W66 1hsVjWZGvvQL+HmobuSvsF8WBMAFgJgYLg0YzBAvwHIk 886be6vbNeAltvPl9I+tjllXkMK5dReMH40ulgKo+Cwb xNQ+RfHhCQIwKgyvL1JGuHB125rdEQEVnMy26bDcC9R+ qJNYj751CEUZxEEGI9cZkD44oHwDvPgF16hpNZGUdo8P GtuH4JwP3hDIpNtGTsQrFWYWL5pUuuQRwA== ) ;; AUTHORITY SECTION: example.com. 86400 IN NS master.example.com. example.com. 86400 IN NS slave.example.com. example.com. 86400 IN RRSIG NS 7 2 86400 20131227171405 ( 20131127171405 40400 example.com. hEGzNvKnc3sXkiQKo9/+ylU5WSFWudbUc3PAZvFMjyRA j7dzcVwM5oArK5eXJ8/77CxL3rfwGvi4LJzPQjw2xvDI oVKei2GJNYekU38XUwzSMrA9hnkremX/KoT4Wd0K1NPy giaBgyyGR+PT3jIP95Ud6J0YS3+zg60Zmr9iQPBifH3p QrvvY3OjXWYL1FKBK9+rJcwzlsSslbmj8ndL1OBKPEX3 psSwneMAE4PqSgbcWtGlzySdmJLKqbI1oB+d3I3bVWRJ 4F6CpIRRCb53pqLvxWQw/NXyVefNTX8CwOb/uanCCMH8 wTYkCS3APl/hu20Y4R5f6xyt8JZx3zkZEQ== ) ;; Query time: 0 msec ;; SERVER: 127.0.0.1#53(127.0.0.1) ;; WHEN: Thu Nov 28 00:01:06 2013 ;; MSG SIZE rcvd: 1335
主服务器配置完成。
DNSSEC 从站配置
从属服务器 只需要启用 DNSSEC 并更改区域文件位置。 编辑 BIND 的主配置文件。
nano /etc/named.conf
如果这些行不存在,请将它们放在 options { }
部分中。
dnssec-enable yes; dnssec-validation yes; dnssec-lookaside auto;
编辑 zone { }
部分内的 file
选项。
zone "example.com" IN { type slave; file "example.com.zone.signed"; masters { 1.1.1.1; }; allow-notify { 1.1.1.1; }; };
重新加载 BIND 服务。
service named reload
检查是否有新的 .signed
区域文件。
[root@slave ~]# ls -l /var/named/slaves/ total 16 -rw-r--r-- 1 named named 472 Nov 27 17:25 example.com.zone -rw-r--r-- 1 named named 9180 Nov 27 18:29 example.com.zone.signed
瞧! 就是这样。 只是为了确保一切正常,如上一节所述,使用 dig
查询 DNSKEY。
使用注册商配置 DS 记录
当我们在 .signed
区域文件之外运行 dnssec-signzone
命令时,还会创建一个名为 dsset-example.com
的文件,其中包含 DS 记录。
root@master:/var/cache/bind# cat dsset-example.com. example.com. IN DS 62910 7 1 1D6AC75083F3CEC31861993E325E0EEC7E97D1DD example.com. IN DS 62910 7 2 198303E265A856DE8FE6330EDB5AA76F3537C10783151AEF3577859F FFC3F59D
这些必须在您的域名注册商的控制面板中输入。 下面的屏幕截图将说明 GoDaddy 上的步骤。
登录到您的域注册商的控制面板,选择您的域,然后选择管理 DS 记录的选项。 GoDaddy 的控制面板如下所示。
这是 dsset-example.com.
文件中的数据分解。
DS 记录 1:
密钥标签: 62910 算法: 7 摘要类型: 1 摘要: 1D6AC75083F3CEC31861993E325E0EEC7E97D1DD
DS 记录 2:
密钥标签: 62910 算法: 7 摘要类型: 2 摘要: 198303E265A856DE8FE6330EDB5AA76F3537C10783151AEF95D3577859FFFC3
dsset-example.com.
文件中的第二个 DS 记录在摘要中有一个空格,但是当以表格形式输入时,您应该省略它。 点击Next,点击Finish和Save记录。
保存这些更改需要几分钟时间。 要检查是否已创建 DS 记录,请查询您的 TLD 的名称服务器。 我们可以做一个更简单的 dig +trace
,而不是查找 TLD 的名称服务器。
root@master:~# dig +trace +noadditional DS example.com. @8.8.8.8 | grep DS ; <<>> DiG 9.8.2rc1-RedHat-9.8.2-0.17.rc1.el6_4.6 <<>> +trace +noadditional DS example.com. @8.8.8.8 example.com. 86400 IN DS 62910 7 2 198303E265A856DE8FE6330EDB5AA76F3537C10783151AEF3577859F FFC3F59D example.com. 86400 IN DS 62910 7 1 1D6AC75083F3CEC31861993E325E0EEC7E97D1DD
确认后,我们可以使用以下任何在线服务检查 DNSSEC 是否正常工作。
第一个工具很简单,而第二个工具为您提供了事物的视觉表示。 这是第一个工具的屏幕截图。
注意我标记的行。 第一个提到了 DS 记录的 Key tag 值 (62910),而第二个 key id (40400) 是保存 ZSK(区域签名密钥)的 DNSKEY 记录。
修改区域记录
每次您通过添加或删除记录来编辑区域时,都必须对其进行签名才能使其正常工作。 所以我们将为此创建一个脚本,这样我们就不必每次都输入长命令。
root@master# nano /usr/sbin/zonesigner.sh #!/bin/sh PDIR=`pwd` ZONEDIR="/var/cache/bind" #location of your zone files ZONE=$1 ZONEFILE=$2 DNSSERVICE="bind9" #On CentOS/Fedora replace this with "named" cd $ZONEDIR SERIAL=`/usr/sbin/named-checkzone $ZONE $ZONEFILE | egrep -ho '[0-9]{10}'` sed -i 's/'$SERIAL'/'$(($SERIAL+1))'/' $ZONEFILE /usr/sbin/dnssec-signzone -A -3 $(head -c 1000 /dev/random | sha1sum | cut -b 1-16) -N increment -o $1 -t $2 service $DNSSERVICE reload cd $PDIR
保存文件并使其可执行。
root@master# chmod +x /usr/sbin/zonesigner.sh
每当您想添加或删除记录时,请编辑 example.com.zone
和 而不是 .signed 文件 。 该文件还负责增加序列值,因此您无需在每次编辑文件时都这样做。 编辑后通过传递域名和区域文件名作为参数运行脚本。
root@master# zonesigner.sh example.com example.com.zone
您不必在从属名称服务器上执行任何操作,因为递增的序列号将确保该区域是否被传输和更新。
从区域漫游保护 DNSSEC 设置
ZoneWalking是一种通过查询NSEC(Next-Secure)记录来查找一个区域的所有资源记录的技术。 NSEC3 已发布,它使用盐“散列”了此信息。 回想一下 dnssec-signzone
命令,我们在其中指定了 -3
选项,然后是另一个精心制作的命令来生成随机字符串。 这是可以使用以下 dig
查询找到的盐。
# dig NSEC3PARAM example.com. @master.example.com. +short 1 0 10 7CBAA916230368F2
所有这些都使区域行走变得困难但并非不可能。 一个坚定的黑客使用 彩虹表 可以破解散列,尽管这需要很长时间。 为了防止这种情况,我们可以定期重新计算这个盐,这使得黑客的尝试是徒劳的,因为在他/她可以找到旧盐的散列之前有一个新的盐。 使用我们之前创建的 zonesigner.sh 脚本创建一个 cron 作业来为您执行此操作。 如果您以 root
运行 cronjob,则不必担心文件所有权。 或者确保您放置 cron 的用户对区域目录 具有 写入权限,对私钥 具有 读取权限(Kexample.com 。*。私人的)。
root@master:~# crontab -e 0 0 */3 * * /usr/sbin/zonesigner.sh example.com example.com.zone
这将每 3 天对该区域进行一次签名,结果将生成新的盐。 您还将收到一封电子邮件,其中包含 dnssec-signzone
命令的输出。