如何在权威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 命令的输出。