第七章:安全配置7.1. 安全假设7.1.1. 权威服务器7.1.2. DNS 解析器7.2. 访问控制列表7.3. Chroot
和 Setuid
7.3.1. chroot
环境7.3.2. 使用 setuid
功能7.4. 动态更新安全7.5. TSIG7.5.1. 生成共享密钥7.5.2. 加载新密钥7.5.3. 指示服务器使用密钥7.5.4. 基于TSIG的访问控制7.5.5. Errors7.6. SIG(0)
BIND 9的设计假设对下面列出的对象的访问仅限于受信任方。不符合本节规定的错误部署不能作为CVE分配或特殊安全敏感问题处理的基础。
未经授权的访问可能会泄露敏感数据、减慢服务器运行速度等。对以下列出的任何对象进行未经授权、意外或不正确的写入都可能导致崩溃、不正确的数据处理或损坏:
存储在磁盘上的所有文件,包括区域文件、配置文件、密钥文件、临时文件等。
客户端使用配置的密钥通过控制套接字进行通信
statistics-channels
用于 update-policy
类型外部的套接字
DNS协议的某些方面没有明确说明,例如处理来自不完全符合DNS协议的DNS服务器的响应。对于这种情况,BIND实施了自己的安全检查和限制,这些检查和限制会随着协议和部署的发展而变化。
默认情况下,区域会故意使用宽松的限制(无限大小、长传输超时等)。这些默认值可能被数据源(区域传输或UPDATE)滥用,以耗尽接收端的资源。
使用服务器资源限制和区域传输部分中列出的配置选项,可以在一定程度上限制恶意区域更改的影响。还应将限制应用于恶意客户端可能被授权使用动态更新的区域。
根据定义,DNS解析器充当流量放大器(traffic amplifiers);在正常运行期间,DNS解析器可以合法地生成比触发它的传入客户端流量更多的传出流量(以数据包或字节计)。DNS协议规范目前没有为此放大指定限制,但BIND实现了自己的限制,以平衡互操作性和安全性。一般来说,如果任何给定场景的流量放大系数低于100个数据包,ISC不会将给定场景作为安全问题处理。随着DNS部署的发展,这些限制可能会发生变化。
DNS解析器收到的所有DNS答案都被视为不受信任的输入,并受到安全性和正确性检查。然而,协议不一致可能会导致意外行为。如果这种意外行为仅限于托管在不符合要求的服务器上的DNS域,则不会被视为BIND中的安全问题。
访问控制列表(Access Control Lists —— ACLs)是地址匹配列表,可以设置和昵称以供将来在allow-notify
(允许通知)、allow-query
(允许查询)、allow-query-on
(允许查询上)、allow-recursion
(允许递归)、blackhole
(黑洞)、allow-transfer
(允许传输)、match-cliens
(匹配客户端)等中使用。
ACL使用户可以更好地控制谁可以访问名称服务器,而不会用大量的IP地址列表弄乱配置文件。
使用ACL和控制访问是个好主意。限制外部各方对服务器的访问有助于防止对服务器的欺骗和拒绝服务(DoS)攻击。
ACL根据最多三个特征匹配客户端:1)客户端的IP地址;2) 用于对请求进行签名的TSIG或SIG(0)密钥(如果有的话);以及3)在EDNS客户端子网选项中编码的地址前缀(如果有的话)。
以下是一个基于客户端地址的ACL示例:
x// Set up an ACL named "bogusnets" that blocks
// RFC1918 space and some reserved space, which is
// commonly used in spoofing attacks.
acl bogusnets {
0.0.0.0/8; 192.0.2.0/24; 224.0.0.0/3;
10.0.0.0/8; 172.16.0.0/12; 192.168.0.0/16;
};
// Set up an ACL called our-nets. Replace this with the
// real IP numbers.
acl our-nets { x.x.x.x/24; x.x.x.x/21; };
options {
...
...
allow-query { our-nets; };
allow-recursion { our-nets; };
...
blackhole { bogusnets; };
...
};
zone "example.com" {
type primary;
file "m/example.com";
allow-query { any; };
};
这允许从任何地址对 example.com
进行权威查询,但只能从 our-nets
中指定的网络进行递归查询,而不能从 bogusnets
中指定的任何网络进行查询。
除了与DNS请求的源地址匹配的网络地址和前缀外,ACL还可以包括指定TSIG或SIG(0)密钥名称的 key
元素。
当BIND 9构建时支持GeoIP,ACL也可用于地理访问限制。这是通过指定格式为的ACL元素来实现的:geoip db database field value
。
field
参数指示要搜索匹配的字段。可用字段包括 country
(国家)、region
(地区)、city
(城市)、continent
(大陆)、postal
(邮政编码)、metro
(地铁代码)、area
(区号)、tz
(时区)、isp
、asnum
和 domain
。
value
是要在数据库中搜索的值。如果字符串包含空格或其他特殊字符,则可以引用该字符串。可以使用字符串“ASNNNN”或整数NNNN指定自治系统编号的 asnum
搜索。如果使用两个字符长的字符串指定国家搜索,则它必须是标准的ISO-3166-1双字母国家代码;否则,它将被解释为该国的全名。同样,如果 region
是搜索词,字符串长度为两个字符,则将其视为标准的两个字母的州或省缩写;否则,它将被视为州或省的全名。
database
字段指示要搜索哪个GeoIP数据库进行匹配。在大多数情况下,这是不必要的,因为大多数搜索字段只能在单个数据库中找到。但是,对continent
或 country
的搜索可以从 city
或 country
数据库中得到答案,因此对于这些搜索类型,指定database
会强制从该数据库而不是其他数据库中回答查询。如果未指定 database
,则首先从安装了 city
数据库的城市数据库中回答这些查询,然后从安装了 countyr
数据库的国家数据库中回答。有效的数据库名称包括country
、city
、asnum
、isp
和 domain
。
一些GeoIP ACL示例:
xxxxxxxxxx
geoip country US;
geoip country JP;
geoip db country country Canada;
geoip region WA;
geoip city "San Francisco";
geoip region Oklahoma;
geoip postal 95062;
geoip tz "America/Los_Angeles";
geoip org "Internet Systems Consortium";
ACL使用“首次匹配”逻辑,而不是“最佳匹配”;如果地址前缀与ACL元素匹配,则认为该ACL已匹配,即使后面的元素更具体地匹配。例如,ACL {10/8; !10.0.0.1;}
实际上会匹配10.0.0.1中的查询,因为第一个元素表示应该接受查询,而第二个元素被忽略。
当使用“嵌套”ACL(即其他ACL中包含或引用的ACL)时,嵌套ACL的负匹配告诉包含ACL继续查找匹配。这使得能够构建复杂的ACL,其中可以同时检查多个客户端特征。例如,要构建一个ACL,仅在查询来自特定网络并且仅在使用特定密钥签名时才允许查询,请使用:
xxxxxxxxxx
allow-query { !{ !10/8; any; }; key example; };
在嵌套的ACL中,任何不在10/8网络前缀中的地址都会被拒绝,从而终止ACL的处理。接受10/8网络前缀中的任何地址,但这会导致嵌套ACL的负匹配,因此包含ACL的ACL会继续处理。如果查询由密钥 example
签名,则接受查询,否则拒绝查询。因此,只有当两个条件都为真时,ACL才会匹配。
Chroot
和 Setuid
在Unix服务器上,通过为 named
指定 -t
选项,可以在chroot环境中运行BIND(使用 chroot()
函数)。这可以通过将BIND放置在“沙箱”中来帮助提高系统安全性,这可以限制服务器受到攻击时造成的损害。
Unix版本的BIND的另一个有用功能是能够以无特权用户(-u
用户)身份运行守护进程。我们建议在使用 chroot
功能时以无特权用户身份运行。
以下是一个示例命令行,用于在 chroot
沙箱 /var/named中
加载BIND,并向用户202运行名为 setuid
的命令行:
/usr/local/sbin/named -u 202 -t /var/named
chroot
环境为了使 chroot
环境在特定目录(例如 /var/named
)中正常工作,该环境必须包含BIND运行所需的所有内容。从BIND的角度来看,/var/named
是文件系统的根;必须调整 directory
和 pid-file
等选项的值以考虑这一点。
与早期版本的BIND不同,named
通常不需要静态编译,也不需要在新根目录下安装共享库。但是,根据操作系统的不同,可能需要设置 /dev/zero
、 /dev/random
、 /dev/log
和 /etc/localtime
等位置。
setuid
功能在运行 named
守护进程之前,请在BIND应写入的文件上使用 touch
实用程序(更改文件访问和修改时间)或 chown
实用程序(设置用户id和/或组id)。
注:
如果 named
守护进程以无特权用户身份运行,则在服务器重新加载时,它无法绑定到新的受限端口。
应严格限制对动态更新工具的访问。在BIND的早期版本中,唯一的方法是基于请求更新的主机的IP地址,在 allow-update
区域选项中列出IP地址或网络前缀。这种方法是不安全的,因为更新UDP数据包的源地址很容易被伪造。另请注意,如果 allow-update
选项允许的IP地址包括执行动态更新转发的辅助服务器的地址,则通过将更新发送给辅助服务器,主服务器可能会受到轻微的攻击,辅助服务器会将更新转发给主服务器及其自己的源IP地址,从而使主服务器毫无疑问地批准它。
出于这些原因,我们强烈建议通过事务签名(transaction signatures —— TSIG)对更新进行加密认证。也就是说,allow-update
选项应仅列出TSIG密钥名称,而不是IP地址或网络前缀。或者,可以使用 update-policy
选项。
一些站点选择将所有动态更新的DNS数据保存在子域中,并将该子域委托给单独的区域。这样,包含关键数据(如公共web和邮件服务器的IP地址)的顶级区域根本不需要允许动态更新。
TSIG(Transaction SIGnatures)是一种用于验证DNS消息的机制,最初在 RFC 2845 中指定。它允许使用共享密钥对DNS消息进行加密签名。TSIG可用于任何DNS事务,当基于IP的访问控制不足或需要覆盖时,作为一种将对某些服务器功能(例如递归查询)的访问限制在授权客户端的方式,或者当消息真实性对服务器的完整性至关重要时,作为确保消息真实性的一种方式,例如动态UPDATE消息或从主服务器到辅助服务器的区域传输。
本节是在BIND中设置TSIG的指南。它描述了配置语法和创建TSIG密钥的过程。
named
支持TSIG进行服务器到服务器的通信,BIND附带的一些工具支持它向 named
发送消息:
-k
、 -l
和 -y
命令行选项支持TSIG,或者在交互式运行时通过 key
命令支持TSIG。-k
和 -y
命令行选项支持TSIG。TSIG密钥可以使用 tsig-keygen
命令生成;命令的输出是一个适合包含在 named.conf
中的 key
指令。密钥名、算法和大小可以通过命令行参数指定;默认值分别为“tsig-key”、HMAC-SHA256和256位。
任何有效的DNS名称字符串都可以用作键名。例如,在名为 host1
和 host2
的服务器之间共享的密钥可以称为“host1-host2”,并且可以使用以下命令生成此密钥:
xxxxxxxxxx
$ tsig-keygen host1-host2. > host1-host2.key
然后可以将此密钥复制到两个主机。两台主机上的密钥名称和密钥必须相同。(注意:将共享密钥从一个服务器复制到另一个服务器超出了DNS的范围。应使用安全传输机制:安全FTP、SSL、ssh、电话、加密电子邮件等。)
tsig-keygen
也可以作为 ddns-confgen
运行,在这种情况下,它的输出包括用于在 named
中设置动态DNS的额外配置文本。有关详细信息,请参阅 ddns-confgen
TSIG密钥生成工具。
对于名为 host1
和 host2
的服务器之间共享的密钥,可以将以下内容添加到每个服务器的 named.conf
文件中:
xxxxxxxxxx
key "host1-host2." {
algorithm hmac-sha256;
secret "DAopyf1mhCbFVZw7pgmNPBoLUq8wEUT7UuPoLENP2HY=";
};
(这与上面使用 tsig-keygen
生成的密钥相同。)
由于此文本包含一个秘密,建议 named.conf
不是全球可读的,或者将 key
指令存储在一个全球可读的文件中,该文件通过 include
指令包含在 named.conf
中。
一旦将密钥添加到 named.conf
中,并且服务器重新启动或重新配置,服务器就可以识别该密钥。如果服务器接收到由密钥签名的消息,则能够验证签名。如果签名有效,则使用相同的密钥对响应进行签名。
向另一个服务器发送请求的服务器必须被告知是否使用密钥,如果是,则使用哪个密钥。
例如,在次要区域的定义中,可以在 primaries
语句中为每个服务器指定一个密钥;在这种情况下,所有SOA QUERY消息、NOTIFY消息和区域传输请求(AXFR或IXFR)都使用指定的密钥进行签名。密钥也可以在主区域或辅助区域的 also-notify
语句中指定,从而使用指定的密钥对NOTIFY消息进行签名。
密钥也可以在 server
指令中指定。如果 host2
的IP地址为10.1.2.3,在 host1
上添加以下内容将导致从 host1
到 host2
的所有请求,包括正常的DNS查询,都使用 host1-host2.
密钥进行签名:
xxxxxxxxxx
server 10.1.2.3 {
keys { host1-host2. ;};
};
keys
语句中可能存在多个密钥,但只使用第一个密钥。由于此指令不包含机密,因此可以在全球可读的文件中使用。
除非 host2
的配置文件中有类似的服务器指令,否则 host2
向 host1
发送的请求将不会被签名。
当任何服务器发送TSIG签名的DNS请求时,它都希望使用相同的密钥对响应进行签名。如果响应未签名,或者签名无效,则拒绝响应。
TSIG密钥可以在ACL定义和ACL指令中指定,如 allow-query
(允许查询)、 allow-transfer
(允许传输)和 allow-update
(允许更新)。上述密钥将在ACL元素中表示为 key host1-host2.
。
以下是一个使用TSIG密钥的 allow-update
指令的示例:
xxxxxxxxxx
allow-update { !{ !localnets; any; }; key host1-host2. ;};
只有当UPDATE请求来自本地网中的地址,并且使用 host1-host2.
密钥进行签名时,动态更新才能成功
有关更灵活的更新策略声明的讨论,请参阅动态更新策略。
处理TSIG签名消息可能会导致几个错误:
在上述所有情况下,服务器都会返回NOTAUTH(未经过身份验证)的响应代码。
BIND部分支持RFC 2535和RFC 2931中指定的DNSSEC SIG(0)事务签名。SIG(0)使用公钥/私钥对消息进行身份验证。访问控制的方式与TSIG密钥相同;可以根据键名在ACL指令中授予或拒绝特权。
当收到SIG(0)签名的消息时,只有当服务器知道并信任密钥时,才会对其进行验证。服务器不会尝试递归获取或验证密钥。
不支持对多个消息TCP流进行SIG(0)签名。
BIND 9附带的唯一生成SIG(0)签名消息的工具是 nsupdate
。