简介:DNS 安全威胁和缓解措施
由于域名系统的开放式分布式设计以及用户数据报协议 (UDP) 的使用,DNS 很容易受到各种形式的攻击。公共或“开放”递归 DNS 解析器尤其容易引发风险,因为它们不会将传入的数据包限制为一组允许的源 IP 地址。我们主要担心两种常见的攻击类型:
- 导致 DNS 缓存投毒的仿冒攻击。 各种类型的 DNS 仿冒和假冒攻击普遍利用,其目的是将用户从合法网站重定向到恶意网站。其中包括 Kaminsky 攻击,攻击者会利用这种攻击性地控制整个 DNS 区域。
- 拒绝服务 (DoS) 攻击。攻击者可能会针对解析器本身发起 DDoS 攻击,或劫持解析器针对其他系统发起 DoS 攻击。使用 DNS 服务器通过大型 DNS 记录/响应大小对其他系统发起 DoS 攻击的攻击称为“放大攻击”。
下面进一步讨论了每类攻击。
缓存中毒攻击
DNS 欺骗攻击有多种变体,可能会导致缓存投毒,但一般情况如下:
- 攻击者如果知道域名不具有权威性,也无法在服务器缓存中进行查询,就会向目标 DNS 解析器发送多次查询。
- 解析器会向其他域名服务器发送请求(攻击者还可以预测其 IP 地址)。
- 在此期间,攻击者会利用受害者的服务器发送伪装的响应,这些伪装响应似乎是来自委托域名服务器。响应包含记录,这些记录最终将请求的网域解析为攻击者控制的 IP 地址。它们可能包含已解析名称的应答记录,更糟糕的是,可能会进一步将授权委派给攻击者拥有的域名服务器,以便他们可以控制整个区域。
- 如果其中一个伪造的响应与解析器的请求(例如,按查询名称、类型、ID 和解析器来源端口)匹配,并且是在真实服务器发出的响应之前收到的,则该解析器接受伪造响应并对其进行缓存,并舍弃真实响应。
- 将来,针对被破解网域或区域的查询会使用缓存中的伪造 DNS 解析进行回答。如果攻击者针对伪造响应指定了非常长的存留时间,则伪造记录会在缓存中保留尽可能长的时间,但不会刷新。
有关 Kaminsky 攻击的详细介绍,请参阅 Kaminsky DNS 漏洞图解指南。
DoS 和扩散攻击
DNS 解析器受到所有网络系统的常规 DoS 威胁。不过,放大攻击尤其令人担忧,因为 DNS 解析器对于利用解析器(响应/请求较大)比率来获得额外的可用带宽的攻击者而言具有吸引力。支持 EDNS0(DNS 的扩展机制)的解析器尤其容易出现问题,因为它们可以返回的数据包要大得多。
在放大场景下,攻击过程如下:
- 攻击者会使用伪造的源 IP 地址发送受害者 DNS 服务器查询。查询可能来自使用同一系统 IP 地址的单个系统或系统网络。查询是针对攻击者知道会造成更大响应(最多几十倍)1(原始查询大小为“放大”攻击的记录)的记录。
- 受害者服务器会向伪造的请求中传递的来源 IP 地址发送大量响应,这会给系统带来过多负担并造成 DoS 情况。
缓解措施
完整的系统级 DNS 漏洞解决方案是 DNSSEC。但是,在实现它之前,开放式 DNS 解析器需要独立采取一些措施来缓解已知威胁。人们提出了很多技术;如需大致了解大多数技术,请参阅 IETF RFC 5452:使 DNS 更能抵御伪造响应的措施。在 Google 公共 DNS 中,我们实现了并推荐以下方法:
- 保护代码免受缓冲区溢出的影响,尤其是负责解析和序列化 DNS 消息的代码。
- 超额预配机器资源,以防止解析器本身遭到直接 DoS 攻击。由于 IP 地址对攻击者来说非常重要,因此根据 IP 地址或子网来阻止查询是不可能的;处理此类攻击的唯一有效方式就是简单消减负载。
- 实现响应数据包的基本域名服务器检查和域名服务器可信度检查,以防止简单的缓存投毒。 这些都是标准机制和健全性检查,任何符合标准的缓存解析器都应执行此类检查。
- 为请求消息添加熵,以降低更复杂的欺骗/缓存中毒攻击(例如 Kaminsky 攻击)的可能性。有许多推荐方法可用于添加熵。下面,我们简要介绍其中每种技术的优势、局限和挑战,并讨论我们如何在 Google 公共 DNS 中实现这些技术。
- 移除重复的查询,以降低出现“生日攻击”的概率。
- 速率限制请求,以防止 DoS 和放大攻击。
- 使用最大带宽监控客户端 IP 的服务,并实现最高的响应请求大小比率。
DNSSEC
域名安全扩展 (DNSSEC) 标准在一些 IETF RFC 中进行了指定:4033、4034、4035 和 5155。
通过验证从域名服务器收到的响应的真实性来实现 DNSSEC 计数器投毒攻击的解析器。每个 DNS 区域维护着一组私钥/公钥对,并且对于每个 DNS 记录,系统都会使用私钥生成并加密唯一的数字签名。然后,通过属于父区域的密钥,通过信任链对相应的公钥进行身份验证。符合 DNSSEC 的解析器会拒绝不含正确签名的响应。DNSSEC 可有效防止响应遭到篡改,因为在实际操作中,如果不访问私钥,签名几乎是不可能的。
从 2013 年 1 月开始,Google 公共 DNS 完全支持 DNSSEC。我们接受并转发 DNSSEC 格式的消息,并验证响应是否正确无误。我们强烈建议其他解析器也这样做。
我们还缓存了 IETF RFC 8198:积极使用 DNSSEC 验证的缓存中指定的 NSEC 响应。这可以减少对实现 DNSSEC 的域名服务器进行 NXDOMAIN 查询,并减少 NSEC 作为否定答案。
客户端加密传输
Google 公共 DNS 支持加密传输协议、DNS over HTTPS 和 DNS over TLS。这些协议可防止篡改、窃取和仿冒,并大幅增强客户端和 Google 公共 DNS 之间的隐私性和安全性。它们与 DNSSEC 相辅相成,可提供经身份验证的端到端 DNS 查询。
实现基本有效性检查
某些 DNS 缓存损坏可能是由请求和响应之间的意外不匹配(不一定是恶意原因)(例如,域名服务器配置错误、DNS 软件存在错误等)。DNS 解析器至少应该进行检查,以验证域名服务器和响应的可信度和相关性。我们建议(并实施)以下所有防御措施:
- 请勿在传出请求中设置递归位,并且始终明确遵循委托链。停用递归位可确保解析器在“迭代”模式下运行,以便您明确查询委托链中的每个域名服务器,而不是允许其他域名服务器代表您执行这些查询。
- 拒绝可疑回复邮件。 请参阅下文,详细了解我们认为“可疑”的情况。
- 请勿根据从之前请求缓存的胶水记录将 A 记录返回给客户端。例如,如果您收到的是 ns1.example.com 的客户端查询,则应重新解析该地址,而不是根据从 .com TLD 域名服务器返回的缓存胶水记录发送 A 记录。
拒绝不符合要求的回复
Google 公共 DNS 会拒绝以下所有内容:
- 响应无法解析或格式错误。
- 键字段与请求中的相应字段不匹配的响应。 包括查询 ID、来源 IP、来源端口、目标 IP 或查询名称。有关 DNS 欺骗行为的完整说明,请参阅 RFC 5452 第 3 节。
- 与请求无关的记录。
- 回答无法重建 CNAME 链的记录。
- 对应的域名服务器不可信的记录(在应答、授权或其他部分中)。 我们会根据域名服务器在给定网域的委托链中所处的位置来确定其“可信度”。Google 公共 DNS 会缓存委托链信息,我们会根据收到的缓存信息验证每个收到的响应,以确定响应域名服务器在响应特定请求时的可信度。
向请求添加熵
一旦解析器强制执行基本健全性检查,攻击者就必须向受害者的解析器发送响应,以匹配查询的 ID、请求的 UDP 端口、(请求的)IP 地址以及原始请求的查询名称。
遗憾的是,这并不容易实现,因为唯一一个标识 ID 的字段(查询 ID)只有 16 位(即 1/65536 的几率可以实现正确)。其他字段的范围也有限,因此唯一组合的总数相对较少。请参阅 RFC 5452,第 7 节,了解相关组合的计算。
因此,挑战在于在 DNS 消息的标准格式中向请求数据包添加尽可能多的熵,让攻击者更加难以成功地在机会窗口内匹配有效的字段组合。我们建议并实施了以下各部分中讨论的所有技术。
我们在 2022 年 7 月的 DNS OARC 38 会议上对此处提到的技术进行了更新的评价。该演示文稿还包含有关域名服务器运算符的建议。
随机选择来源端口
作为基本步骤,切勿允许传出请求数据包使用默认 UDP 端口 53,或采用可预测的算法来分配多个端口(例如,简单的增量操作)。请尽可能使用系统中允许的端口(1024 至 65535),并使用可靠的随机数生成器分配端口。 例如,Google 公共 DNS 使用大约 15 位,允许大约 32000 个不同的端口号。
请注意,如果您的服务器部署在防火墙、负载平衡器或执行网络地址转换 (NAT) 的其他设备之后,这些设备可能会对传出数据包上的端口进行随机化处理。请务必将 NAT 设备配置为停用端口非随机分配。
随机选择域名服务器
一些解析器在向根、TLD 或其他域名服务器发送请求时,会根据最短距离(延迟时间)选择域名服务器的 IP 地址。我们建议您随机设置目标 IP 地址,以在传出请求中添加熵。在 Google 公共 DNS 中,我们只需在各个地区的已配置域名服务器中随机选择一个域名服务器,这在某种程度上有利于快速可靠的域名服务器。
如果您担心延迟,则可以使用往返时间 (RTT) 频段,该模式包括在低于特定延迟时间阈值的地址范围内进行随机化处理(例如 30 毫秒、300 毫秒等)。
DNS Cookie
RFC 7873 定义了一个 EDNS0 选项,用于向 DNS 消息添加 64 位 Cookie。支持客户端的 DNS Cookie 包含一个随机 64 位 Cookie,也可选择性地在请求中包含一个服务器 Cookie(如果已知)。如果支持服务器在请求中发现有效的 Cookie 选项,那么会在响应中反映客户端 Cookie 和正确的服务器 Cookie。然后,支持客户端通过验证响应中的客户端 Cookie 来验证响应是否来自预期的服务器。
如果域名服务器不支持 DNS Cookie,那么可以使用以下两个选项添加熵。
查询名称中的大小写随机化
DNS 标准要求域名服务器处理名称时不区分大小写。例如,名称 example.com
和 EXAMPLE.COM
应解析为相同的 IP 地址2。此外,除少数域名服务器外,其他所有域名服务器均在响应中回显名称(与请求中显示的名称一致),从而保留原始大小写。
因此,向请求添加熵的另一种方法是随机变化查询域名中的字母大小写。此技术也称为“0x20”,因为位 0x20 用于设置 US-ASCII 字母的大小写,最初是在 IETF 互联网草案 DNS 标签中使用位 0x20 改进事务标识中提出的。使用这种方法时,域名服务器响应不仅必须与查询名称匹配,还必须与名称字符串中每个字母的大小写匹配;例如 wWw.eXaMpLe.CoM
或 WwW.ExamPLe.COm
。这可能会对顶级网域和根网域的查询增加或几乎没有熵,但对大多数主机名都有效。
我们在实现此技术时发现一个重大挑战,即某些域名服务器不符合预期的响应行为:
- 某些域名服务器在响应时不区分大小写,无论请求中的大小写如何,它们都会正确返回相同的结果,但响应与请求中的名称完全一致。
- 其他域名服务器的响应方式完全区分大小写(违反了 DNS 标准):处理此类请求所用的名称会因请求中的大小写而异,要么根本无法回复,要么返回与请求中的名称确切大小写错误的 NXDOMAIN 响应。
- 除
arpa
区域中的 PTR 查询外,部分域名服务器可正常运行。
对于这两种类型的域名服务器,更改查询名称的大小写都会产生不良结果:对于第一个组,响应与伪造的响应是无法区分的;对于第二个组,响应(如有)可能完全不正确。
目前,此问题的解决方案是仅对已知正确地应用标准的域名服务器进行随机分配。我们还会根据日志来列出各个子网域的异常子网域。如果看似来自这些服务器的响应不包含正确的大小写,我们会拒绝该响应。已启用的域名服务器可处理 70% 以上的出站流量。
在查询名称前面附加 Nonce 标签
如果解析器不能直接从缓存中解析名称,或者无法直接查询权威域名服务器,则必须跟踪根服务器或顶级域名域名服务器的引荐。在大多数情况下,向根服务器或 TLD 域名服务器发送请求后,系统会将其引荐给其他域名服务器,而不是尝试将其名称解析为 IP 地址。因此,对于此类请求,在查询名称中附加随机标签应该可以增加请求的熵,同时又不会承担解析不存在的名称的风险。也就是说,向引用域名服务器发送请求以获取以 Nonce 标签为前缀的名称(例如 entriih-f10r3.www.google.com
),返回的结果应该与 www.google.com
的请求相同。
虽然在实践中,此类请求占传出请求的比例低于 3%,但一般情况是由于常规流量(因为大多数查询可以直接从缓存或单个查询得到响应),但这正是攻击者试图强制解析器发出的请求的类型。因此,此方法对于防范 Kaminsky 式攻击非常有效。
要实现此方法,必须保证 Nonce 标签仅用于保证会发生引荐的请求;也就是说,响应不包含答案部分中的记录。但是,我们在尝试定义一组此类请求时遇到了一些挑战:
- 实际上,某些国家/地区代码的 TLD (ccTLD) 域名服务器是其他第二级 TLD (2LD) 的权威。虽然 2LD 有两个标签,但其行为与 TLD 一样,因此它们通常由 ccTLD 域名服务器进行处理。例如,
.uk
域名服务器也是mod.uk
和nic.uk
可用区的权威,因此也是这些可用区中包含的主机名,例如www.nic.uk
、www.mod.uk
等。也就是说,发送至 ccTLD 域名服务器以解析此类主机名的请求不会产生引荐流量,但会产生权威答案;将 Nonce 标签附加到此类主机名会导致名称无法解析。 - 有时,通用 TLD (gTLD) 域名服务器会针对域名服务器返回非授权响应。也就是说,有些域名服务器主机名刚好位于 gTLD 区域,而不是其网域的区域。gTLD 使用其数据库中任何粘合记录返回这些主机名的非权威答案,而不是返回引荐来源。例如,域名服务器
ns3.indexonlineserver.com
过去位于.COM
gTLD 可用区,而非位于indexonlineserver.com
可用区。当我们向n3.indexonlineserver.com
的 gTLD 服务器发出请求时,我们得到的是一个 IP 地址,而不是引荐来源。但是,如果我们在前面添加了一个 Nonce 标签,则会收到指向indexonlineserver.com
的引荐,因此之后无法解析主机名。因此,对于需要从 gTLD 服务器进行解析的域名服务器,我们无法附加 Nonce 标签。 - 可用区和主机名的授权随时间而变化。这样一来,一旦委托链发生变化,原来可解析的 Nonce 前缀将变得无法解析。
为应对这些挑战,我们针对主机名附加了例外配置,而这些主机名无法附加 Nonce 标签。根据我们的服务器日志,这些主机名的 TLD 域名服务器会返回非引荐响应。我们会持续审核例外列表,确保其始终有效。
移除重复的查询
DNS 解析器容易受到“生日攻击”的影响,这种攻击称为数学方法,即利用数学的“生日违例”,这种匹配的可能性不需要大量输入。生日攻击涉及向受害者的服务器发送大量泛滥的响应以及初始查询,这些请求依赖于解析器发出针对单一名称解析的多个请求。发出的传出请求数量越多,攻击者将其中某个请求与伪造响应匹配的可能性就越大:攻击者只需要大约 300 个正在发出的请求,才能 50% 成功地获得伪造响应,而 700 个请求则可以接近 100% 成功。
为防御此攻击策略,您应该舍弃出站队列中的所有重复查询。例如,对于相同的查询名称、查询类型和目标 IP 地址,Google 公共 DNS 决不允许一个未完成的请求。
速率限制查询
防止拒绝服务攻击给开放式递归 DNS 解析器带来了几个特殊的挑战:
- 开放式递归解析器是容易造成扩张攻击的攻击目标。它们是高容量、高可靠性的服务器,其可产生比典型权威域名服务器更大的响应,尤其是当攻击者可以将大型响应注入到缓存中时。为了防止开放式服务器用于在其他系统上发起攻击,开放式 DNS 服务的任何开发者都要承担责任。
- 放大攻击可能很难检测到。 攻击者可以通过数千个开放式解析器发起攻击,这样每个解析器只能看到一小部分查询总量,无法提取表明其已被破解的明确信号。
- 您必须屏蔽恶意流量,而不会影响普通用户的 DNS 服务。DNS 是一项重要的网络服务,因此关闭服务器来中断攻击不可行,也不要长时间拒绝任何给定客户端 IP 的服务。解析器必须能够在攻击开始后立即快速阻止攻击,并在攻击结束后立即恢复完全正常运行的服务。
防范 DoS 攻击的最佳方法是施加速率限制或“限制”机制。Google 公共 DNS 实现了两种速率控制:
- 对向其他域名服务器发出的请求进行速率控制。 为了保护其他 DNS 域名服务器免受可能从解析器服务器启动的 DoS 攻击,Google 公共 DNS 对每个域名服务器 IP 地址的传出请求强制执行 QPS 限制。
控制对客户端的传出响应的速率。 为保护任何其他系统免受可能从解析器服务器启动的放大和传统分布式 DoS (botnet) 攻击,Google 公共 DNS 对客户端查询执行两种类型的速率限制:
- 为防范传统的基于卷的攻击,每个服务器都实施了每个客户端 IP 地址的 QPS 和平均带宽限制。
- 为了防止放大攻击(即利用对小查询的大规模响应),每台服务器都会实施每个客户端 IP 的最大平均放大系数。平均放大系数是一个可配置的响应查询大小,该比率是根据我们的服务器日志中观察到的历史流量模式确定的。
如果来自一个来源 IP 地址的 DNS 查询超过 QPS 速率上限,则超出上限的查询将被丢弃。 如果来自一个来源 IP 地址的 UDP DNS 查询持续超过平均带宽或放大限制(偶尔会通过大型响应),则查询可能会被丢弃,或者只能发送小型响应。较小的响应可能是错误响应,也可能是设置了截断位的空响应(这样大多数合法查询都将通过 TCP 重试并成功)。并非所有系统或程序都会通过 TCP 重试,而且 TCP 上的 DNS 可能会被客户端上的防火墙阻止,因此某些应用在回复被截断后可能无法正常运行。尽管如此,在大多数情况下,截断仍可以让符合 RFC 的客户端正常运行。
-
请注意,尽管域名中允许使用大写字母和小写字母,但大小写不会附加任何符号。也就是说,系统会将拼写相同但大小写不同的两个名称视为相同的名称。