DNSSEC依靠数字签名保证DNS应答报文的真实性和完整性。权威域名服务器用自己的私有密钥对资源记录(Resource Record, RR)进行签名,解析服务器用权威服务器的公开密钥对收到的应答信息进行验证。如果验证失败,表明这一报文可能是假冒的,或者在传输过程、缓存过程中被篡改了。
一个支持DNSSEC的解析服务器(RFC4033中Security-Aware Resolver)向支持DNSSEC的权威域名服务器(Security-Aware Name Server)请求域名www.test.net.时,它除了得到一个标准的A记录(包含IPv4地址)以外,还收到一个同名的RRSIG记录,其中包含test.net这个权威域的数字签名,它是用test.net.的私有密钥来签名的。为了验证这一签名的正确性,解析服务器可以再次向test.net的域名服务器查询响应的公开密钥,即名为test.net的DNSKEY类型的资源记录。然后解析服务器就可以用其中的公钥验证上述www.test.net. 记录的真实性与完整性。
配置或布署DNSSEC有两种场景:
(1)配置安全的域名解析服务器(Resolver),该服务器可以保护使用它的用户,防止被DNS 欺骗攻击。这里只涉及数字签名的验证工作。
(2)配置安全的权威域名服务器(Name Server),对权威域的资源记录进行签名,保护服务器不被域名欺骗攻击。
首先,在BIND的配置文件(一般是/etc/named.conf)中打开DNSSEC选项,比如:
options {
directory “/var/named”;
dnssec-validation yes;
….
};
其次,要给解析服务器配置可信锚(Trust Anchors),也就是你所信任的权威域的DNSKEY。理想情况下我们可以配置一个根的密钥就够了,但是目前DNSSEC还没有完全布署的情况下,我们需要配置很多安全岛(Secure Island)的密钥。可以从很多公开的网站下载这些可信域的DNSKEY文件,包括:
(1)Root Zone DNSSEC Trust Anchors:https://www.iana.org/dnssec/。2010年7月布署实施。如果DNSSEC全部布署成功,这一个公开密钥就足够了。
(2)The UCLA secspider : https://secspider.cs.ucla.edu,由美国加州大学洛杉矶分校(UCLA)张丽霞教授的实验室维护。
(3)The IKS Jena TAR:https://www.iks-jena.de/leistungen/dnssec.php
这些文件大概是这样的格式:
trusted-keys {
“test.net.” ?256 3 5? “AQPzzTWMz8qS…3mbz7Fh
……
….fHm9bHzMG1UBYtEIQ==”;
“193.in-addr.arpa.” 257 3 5 “AwEAAc2Rn…HlCKscYl
kf2kOcq9xCmZv….XXPN8E=”;
};
假设上述trust anchors的文件为/var/named/trust-anchors.conf,则在/etc/named.conf中增加下面一行:
include “/var/named/sec-trust-anchors.conf”;
在完成上述配置修改之后重新启动named进程,然后选择一个trust anchor文件中有的区或者它下一级的域名,在解析服务器上用dig测试一下,例如:
#dig @127.0.0.1 +dnssec? ?test.net.? SOA
如果配置正确,应该返回test.net的SOA记录和相应的RRSIG记录,另外返回的头部中应该包含AD标志位,表示DNSSEC相关的数字签名验证是正确的,类似下面的样子:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1397
;; flags: qr rd ra?ad; QUERY: 1, ANSWER: 2, AUTHORITY: 2, ADDITIONAL: 3
如果没有得到期望的结果,需要查看DNS的日志来找出问题。BIND为DNSSEC相关的事件增加了一个dnssec类别,可以在/etc/named.conf配置日志如下:
logging {
channel dnssec_log {
file “log/dnssec” size 20m;? ?// a DNSSEC log channel 20m;
print-time yes; ??????????????????// timestamp the entries
print-category yes; ?????????// add category name to entries
print-severity yes; ?????????// add severity level to entries
severity debug 3;??????? ?// print debug message <= 3 t
};
};
category dnssec { dnssec_log; };
首先为你的区(zone)文件生成密钥签名密钥KSK:
# cd /var/named
# dnssec-keygen -f KSK -a RSASHA1 -b 512 -n ZONE test.net.
Ktest.edu.+005+15480
然后生成区签名密钥ZSK:
# dnssec-keygen -a RSASHA1 -b 512 -n ZONE test.net.
Ktest.edu.+005+03674
其中的-a 参数是签名算法,-b是密钥长度。上述命令共产生两对DNSKEY密钥(共四个文件),分别以.key和.private结尾,表明这个文件存储的是公开密钥或私有密钥。
签名之前,你需要把上面的两个DNSKEY写入到区文件中
#cat “$INCLUDE Ktest.net.+005+15480.key” >> db.test.net
# cat “$INCLUDE Ktest.net.+005+03674.key” >> db.test.net
然后执行签名操作:
# dnssec-signzone -o test.net. db.test.net
db.test.net.signed
上面的-o选项指定代签名区的名字。生成的db.test.net.signed
然后修改/etc/named.conf如下:
options? {
directory “/var/named”;
dnssec-enable yes;
};
zone “test.net” {
type master;
file “db.test.net.signed”;
};
记住,你每次修改区中的数据时,都要重新签名:
# dnssec-signzone -o test.net -f db.test.net.signed.new db.test.net.signed
# mv db.test.net.signed db.test.net.signed.bak
# mv db.test.net.signed.new db.test.net.signed
# rndc reload test.net
要让其他人验证你的数字签名,其他人必须有一个可靠的途径获得你的公开密钥。DNSSEC通过上一级域名服务器数字签名的方式签发你的公钥。
用dnssec-signzone时,会自动生成keyset-文件和dsset-开头的两个文件,分别存储着KSK的DNSKEY记录和DS记录。作为test.net区的管理员,你需要把这两个文件发送给.net的管理员,.net的管理员需要把这两条记录增加到.net区中,并且用.net的密钥重新签名。
test.net.????????????? 86400?? IN NS?? ns.test.net.
86400?? DS????? 15480 5 1 (
F340F3A05DB4D081B6D3D749F300636DCE3D
6C17 )
86400?? RRSIG?? DS 5 2 86400 20060219234934 (
20060120234934 23912?? net.
Nw4xLOhtFoP0cE6ECIC8GgpJKtGWstzk0uH6
YWInWvWx12IiPKfkVU3F0EbosBA= )
? ?因为安全和DNS服务器性能,如果没有ACL,那么任何人都可以到我们的DNS服务器上做递归查询,这样是非常危险的。而且DNS的区域传送是多主复制,如果不设置ACL,那么任何主机都可以到我们的DNS上来做完全区域传送,这也是很危险的。
allow-transfer { ip;|none;}; //允许做区域传送的指令。
allow-query { ip;|none;}; //允许做查询的指令。
allow-recursion { ip;|none;}; //允许做递归查询的ip列表,一般来说只允许给本地客户端做递归查询。
allow-update { ip;|none; }; //用于DDNS(动态DNS:与DHCP联动),比较危险,一般不允许更新数据文件。
以上4段可以放到全局配置中对全局配置生效,也可放在某个区域中,只针对于某个区域生效;而allow-recursion参数要加入到全局配置中,其他两项一般是放到区域配置中。
如果allow-transfer 和 allow-query 放到区域配置中一般后期修改ip地址会非常的麻烦,所以可以定义acl访问规则:
acl只有先定义才可以使用,因此acl定义必须在acl调用的最上方即放在配置文件的最上方。
acl ?string ?{ address_match_element; ...};
acl acl_name {
ip;具体的ip地址
net/prelen;表示一个网段
};
例如:
acl mynet {
172.168.179.110
172.168.179.0/24
};
allow-query ????{ localhost; };
allow-query ????{ mynet; };
bind 内置的 acl:
none :没有一个主机
any :任意主机
localhost :本地主机
localnets:本机的IP同掩码