DNS安全与稳定性
1. 域名劫持
域名劫持一直是困扰许多开发者的问题之一,其表现即域名A应该返回的DNS解析结果IP1被恶意替换为了IP2,导致A的访问失败或访问了一个不安全的站点。下面我们一起看看几种常见的域名劫持的场景。
一种可能的域名劫持方式即黑客侵入了宽带路由器并对终端用户的Local DNS进行篡改,指向黑客自己伪造的Local DNS,进而通过控制Local DNS的逻辑返回错误的IP信息进行域名劫持。另一方面,由于DNS解析主要是基于UDP协议,除了上述攻击行为外,攻击者还可以监听终端用户的域名解析请求,并在Local DNS返回正确结果之前将伪造的DNS解析响应传递给终端用户,进而控制终端用户的域名访问行为。
上述攻击行为的影响面相对比较有限,另一种我们最常碰到的域名劫持现象是缓存污染。我们知道在接收到域名解析请求时,Local DNS首先会查找缓存,如果缓存命中就会直接返回缓存结果,不再进行递归DNS查询。这时候如果Local DNS针对部分域名的缓存进行更改,比如将缓存结果指向第三方的广告页,就会导致用户的访问请求被引导到这些广告页地址上。
对比第一种攻击,这类缓存污染往往能带来更明显的群体伤害,比如某个省份某个运营商的用户群可能因为该地区Local DNS的缓存污染而导致访问服务异常。这类缓存污染行为往往是间歇性、局部性发生的,没有明显的规律,导致开发者很难对其进行量化、评估、预防。
有的同学可能会问,“我使用了HTTPS,是否就可以避免域名劫持的问题”,答案是否定的。域名解析环节发生在网络加密请求交互之前,试想一下,如果客户端还没有服务端的确切地址信息,我们又如何知道应该和谁进行加密的握手协商与通信呢?
2. 调度不精准
除了域名劫持问题,基于传统Local DNS的域名解析还会带来域名调度精准性的问题。对于类似CDN域名访问这类需要按地域、运营商进行智能解析调度的场景,精准调度的诉求是十分强烈的。
关于调度不精准的原因,我们主要可以从两个方面来探究一下。第一个常见的问题即解析转发。
部分Local DNS供应商为了降低运营成本,会将请求到自己节点的域名解析请求转发给其他供应商的Local DNS节点,如上图所示。假如用户请求解析一个CDN域名cdn.aliyun.com,用户分配到的Local DNS A为了节省成本,把该次请求转发给了另一运营商的Local DNS B,权威DNS在进行域名解析时会根据Local DNS的IP信息进行智能调度,即权威DNS会根据Local DNS B的IP78.29.29.1进行调度,分配与78.29.29.1相同运营商并且地理位置最近的CDN节点78.29.29.2,然而这个CDN节点对于终端135.35.35.1而言并不是最优的CDN节点,他们分属不同的运营商,并且地理位置上可能相隔很远。这类解析转发行为会严重影响域名解析的精准性并对用户业务访问延迟带来影响。
除了解析转发对调度精准性带来的影响外,Local DNS的布署情况同样影响着域名智能解析的精准性。
如上图所示,部分运营商Local DNS的布点受成本因素制约分布并不均匀,比如在东部地区部署比较密集,但在西部地区部署比较稀疏。这时候当一位西藏的用户准备访问CDN节点时,我们预期他应该会被调度到西藏的CDN节点A上以实现就近接入和访问加速。但由于Local DNS的资源有限,西部地区的终端用户被统一调度到青海的Local DNS B上,这时候权威DNS根据Local DNS B的IP进行CDN域名的智能解析,并将青海的CDN节点B返回给西藏用户,导致用户的网络访问延迟上升。另一种我们实际发现的情况是Local DNS的分配甚至并非遵循就近原则,比如有实际案例显示西藏的用户甚至被分配了北京的Local DNS节点C,导致西藏的用户在进行CDN资源访问时被调度到了北京的CDN节点C上,类似的由于调度精度的缺失带来的访问体验的影响是非常严重的。
3. 解析生效滞后
部分业务场景下开发者对域名解析结果变更的生效时间非常敏感(这部分变更操作是开发者在权威DNS上完成的),比如当业务服务器受到攻击时,我们需要最快速地将业务IP切换到另一组集群上,这样的诉求在传统域名解析体系下是无法完成的。
Local DNS的部署是由各个地区的各个运营商独立部署的,因此各个Local DNS的服务质量参差不齐。在对域名解析缓存的处理上,各个独立节点的实现策略也有区别,比如部分节点为了节省开支忽略了域名解析结果的TTL时间限制,导致用户在权威DNS变更的解析结果全网生效的周期非常漫长(我们已知的最长生效时间甚至高达48小时)。这类延迟生效可能直接导致用户业务访问的异常。
4. 延迟大
DNS首次查询或缓存过期后的查询,需要递归遍历多个DNS服务器以获取最终的解析结果,这增加了网络请求的前置延时时间。特别是在移动互联网场景下,移动网络质量参差不齐,弱网环境的RTT时间可能高达数百毫秒,对于一次普通的业务请求而言,上述延时是非常沉重的负担。另一方面,弱网环境下的解析超时、解析失败等现象屡见不鲜,如何合理优化DNS解析对于整体网络访问质量的提升至关重要。
5. DNS解析异常
DNS时间是指从浏览器发出域名解析请求开始到收到解析结果结束。如果操作系统配置有多个DNS服务器,浏览器会同时尝试向多个DNS服务器发出请求,以最早收到解析结果的数据为准。
DNS时间可能会远远大于单次dig的时间,原因是当浏览器向DNS服务器发起查询请求后,如果在指定时间内没有收到响应,会重新向此DNS服务器发起查询请求,直到收到一次可用的DNS响应或到达总超时时间(大概11秒左右)。此时DNS时间为多次DNS查询时间总和。
当浏览器使用UDP协议向DNS服务器发起请求后, DNS服务器如果返回flags标记包含TC标记,则代表消息由于太长被截断,浏览器会使用tcp协议重新发起dns请求,如果服务器不支持tcp方式的dns请求,就会造成tcp请求20秒超时后,浏览器尝试再次利用上次不完整的udp数据,从中解析ip并使用。
总结:
DNS时间2-11秒:表现为DNS解析成功,但时间超过2秒,甚至到达11秒, 原因是DNS的超时重试。发生此现象时在网络层抓包会发现多次dns查询数据
DNS时间超20秒:表现为DNS解析成功,但时间超过20秒,原因是DNS服务器返回flags标记包含TC标记,浏览器使用tcp协议重新发起dns请求,而服务器不支持tcp方式的dns请求,造成DNS请求 20秒超时。通常造成这个现象的原因是cname层级过大或A记录过多,导致数据量超过单个MTU的限制,此时需建议客户去协调cdn修改DNS解析结果。发生此现象时在网络层抓包会发现dns响应数据里面flags标记包含TC标记,并且浏览器向DNS服务器发起多次TCP建立连接请求。
6. 不同浏览器的DNS超时重发机制
- Chrome浏览器(37.0.2062.124 m)
1、在Win7环境下,DNS超时重发的时间间隔为:2s、2s、2s、2s(在这个时刻重复发2个DNS请求)、2s、4s,再经过大约14s左右,按上述时间间隔再重发一轮。
当DNS服务器有两个的时候,如下图:
1、在Win7环境下,DNS超时重发的时间间隔是:2s、2s、4s。
DNS服务器有两个的时候,如下:
2、Ubuntu-12.04环境下,DNS超时重发时间间隔为5s,重发16次。
DNS服务器配置为两个的时候,时间间隔仍是5s,两个服务器轮询,重复32次,如下图:
Win7环境下,DNS超时重发时间间隔为:2s、2s、4s、4s、2s、2s、4s。
DNS服务器为两个的时候,如下图:
7. DNS缓存机制
浏览器DNS缓存机制分析
经常做Web开发的工程师,都会遇到需要将某个域名绑定到特定IP上,进行测试的情况。大家一般都会用修改hosts文件的方式来解决,但是经常也会遇到修改hosts不生效的情况,而且有时生效,有时不生效的情况也有发生,这到底是为什么呢?
关于DNS缓存的机制,有一篇非常详细的文章What really happens when you navigate to a URL。
简单来说,一条域名的DNS记录会在本地有两种缓存:浏览器缓存和操作系统(OS)缓存。在浏览器中访问的时候,会优先访问浏览器缓存,如果未命中则访问OS缓存,最后再访问DNS服务器(一般是ISP提供),然后DNS服务器会递归式的查找域名记录,然后返回。
DNS记录会有一个ttl值(time to live),单位是秒,意思是这个记录最大有效期是多少。经过实验,OS缓存会参考ttl值,但是不完全等于ttl值,而浏览器DNS缓存的时间跟ttl值无关,每种浏览器都使用一个固定值。
这里有一篇文章,做过详细的测试Why Web Browser DNS Caching Can Be A Bad Thing:
后来我也做过测试,Mac下Chrome(23.0.1271.101)的DNS缓存时间是1分钟。Safari下DNS缓存时间大约为10秒。