HTTPS上的DNS(DoH)乱局
作者:Joff Thyer //
这个周一早晨醒来时,我认为是时候重新审视我的家庭网络中的域名服务(DNS)配置了。(这个想法也源于2021年在内华达州雷诺市Wild West Hackin’ Fest活动中与Paul Vixie的多次讨论。)
背景而言,我从不认为应该依赖本地互联网服务提供商(ISP)的DNS基础设施。无意冒犯,但我始终认为ISP基础设施如同用胶带和铁丝勉强维系,而我向来是个喜欢"自己动手"的人。
换句话说:“伙计们,只需给我光纤到以太网的接口,路由我的静态地址,传递我的数据包,剩下的交给我。“我很幸运找到一家恰好如此操作的ISP,他们甚至表示如果我拥有地址块,可以传递边界网关协议(BGP)表给我。这简直是天籁之音!
毫不奇怪,我曾管理过拥有数千个端点的大型网络,而我的家庭网络也运行得井井有条。我自行部署路由、网络地址转换(NAT)、动态主机配置协议(DHCP)和DNS服务。只要上游正常传递数据包,我的网络就坚如磐石。
现在进入令人不安的讨论。我们处于监控资本主义时代,全球互联网社区纵容众多公司通过挖掘我们持续产生的数据副产品牟利。
DNS是互联网的基础设施,其设计本质就是高度分布式的!完全可以在自己的网络中运行DNS服务器,并通过DHCP告知网络端点:你的DNS才是域名到IP地址转换的正统之地。遗憾的是,家庭网络用户大多缺乏相关技能,只能依赖漏洞百出的家用路由器产品。
当DNS遭遇监控资本主义,糟糕的事情就会发生。任何明文协议被网络嗅探并用于牟利时,你的隐私正在被侵犯,你正在成为巨额收入的来源。
运行自己的DNS服务器有个微小优势:缓存机制。本地DNS服务器代表客户端存根解析器(端点)发出的请求都会带有生存时间(TTL)缓存值。你的DNS服务器会在TTL秒数内"记住"查询答案。
如果不将所有请求转发给其他DNS提供商(如8.8.8.8),你的DNS服务器必须请求根域名服务器协助解析。下图展示了查询www.whitehouse.gov时本地DNS服务器的行为流程。
问题何在?作为安全专业人士,我们热爱强加密,而DNS显然不够理想——它没有加密。DNSSEC?抱歉,它只确保应答准确性/防止欺骗,解决缓存中毒问题,但不保护传输中数据。
各大浏览器厂商提出了有史以来最糟糕的解决方案:通过HTTPS传输DNS请求(RFC 8484)。HTTPS确实加密了,但请回想监控资本主义的问题——当DNS流量被发送到浏览器厂商的基础设施,你的数据反而更易被监控。这实际上导致了数据控制权的集中垄断!高度分布式架构的稳定性突然被少数巨头掌控,开放标准和自由互联网的原则正被数据挖掘者颠覆。
从协议角度看,我们正在混淆流——HTTP是"超文本传输协议”,而DNS绝非超文本!结果形成了垂直协议栈的单一浏览器厂商锁定。这是我们想要的吗?这是正确的解决方案吗?
我陷入深刻矛盾:强加密本是好事,安全专业人士理应支持经过验证的强加密,但当隐私被如此彻底侵犯时,我无法支持这种做法。更矛盾的是,我也无法确保本地ISP没有挖掘我的加密数据。
另一种DNS加密形式DNS over TLS(DoT,RFC 7858)已存在多年。简言之,DoT至少在TCP 853端口建立适当的TLS服务,以标准合规方式实现加密。但DoT作为新协议面临实施挑战——如何让客户端存根解析器正确使用它?虽然可以通过DHCP选项配置,但仍需操作系统厂商在存根解析器代码中正确实现TLS支持。
不出所料,“正确方案"往往不敌"便捷方案”。DoT需要大量改变,而人们厌恶改变——尤其是对DNS这种如电力般普及的基础服务。
(数据监控话题需要公允看待)以下是主流DoH提供商列表,许多声称通过运营弹性和过滤恶意软件/广告域名提供增值服务:
- cloudflare-dns.com(隐私政策见其博客)
- dns.adguard.com(服务概述见其知识库)
- dns.google(将数据挖掘作为收入来源)
- dns.nextdns.io(见其隐私政策)
- dns.opendns.com(思科商业服务,见使用条款)
- dns.quad9.net(见隐私声明)
平心而论,除个别例外,多数提供商都有较强的隐私声明。我最强烈的反对在于协议栈的破坏,以及浏览器无视本地网络配置擅自接管客户端存根解析器功能。这对需要严格管控网络协议的大型企业完全不可接受。
这些DoH提供商大多也支持DoT。回到周一早晨的目标,我最终形成以下结论:
- 强烈建议有能力者运行自己的内部DNS服务器
- 需要保持诊断和监控内部DNS流量的能力
- 自建DNS服务器可配置域名过滤服务(推荐Pi-Hole项目)
- 警惕ISP将监控资本主义作为收入来源
- 虽不愿破坏DNS原始的分布式美感,但强加密始终有益
我决定继续运行自己的DNS服务器,但使用DoT加密到Quad9的流量。Quad9似乎最具公益属性。同时通过iptables动态IP集阻止所有公共DoH提供商(需定期更新域名列表)。这意味着直接阻止到特定IP的TCP 443流量——就因为有人觉得协议混用是个好主意(叹气)。
Stubby部署
我的边界防火墙基于Ubuntu,需要找到能监听DNS请求并通过DoT转发到Quad9的软件。选择使用名为"Stubby"的DNS隐私守护进程(https://dnsprivacy.org)。安装命令:sudo apt install stubby
。
Stubby作为本地DNS隐私存根解析器,通过TLS连接发送加密查询。其配置文件为/etc/stubby/stubby.yml,Quad9提供了现成配置(参考其支持文档)。关键配置包括:
tls_authentication: GETDNS_AUTHENTICATION_REQUIRED
:强制使用TLS且无回退tls_query_padding_blocksize: 128
:使用EDNS0填充隐藏查询尺寸edns_client_subnet_private: 1
:阻止发送客户端子网信息round_robin_upstreams: 1
:轮询上游服务器idle_timeout: 10000
:保持TCP连接降低开销listen_addresses: 127.0.0.1@8053
:绑定本地端口供Bind9使用
Bind9配置
修改Bind配置使其将请求"转发"到本地Stubby实例。有两种选择:forward only
(仅转发)或forward first
(转发失败时回退标准DNS)。我的配置采用后者,在/etc/bind/named.conf的options部分添加转发地址。
确保Stubby运行并启用开机自启:systemctl enable stubby
。最后用rndc reload
重载Bind,现在发往互联网的DNS流量已加密至Quad9。
防火墙配置
使用iptables实施以下规则:
- 允许出站TCP 853到Quad9地址
- 创建包含常见DoH提供商的IP集并阻止其流量
- 阻止任何端点绕过内部DNS服务器
维护DoH提供商IP集的脚本可通过定期DNS查询更新anycast地址。在crontab设置定时任务即可持续更新。
假设防火墙是边界设备且执行NAT转发,需要添加规则阻止转发到DoH列表的流量。同时确保Stubby能出站与Quad9通信。最后关键规则是阻止内部网络(如10.0.0.0/8)端点直接访问外部DNS(如Google硬编码的8.8.8.8)。
至此,我通过加密发往Quad9的DNS流量获得了暂时的安心,同时保留监控内部DNS流量的能力。这实现了加密、隐私、安全与运营可用性的平衡。祝你在应对DoH乱局的征途中一帆风顺!