EDIT 2021/5/30:根据 Matters 的评论与现实中的草案进展,进行大量修正与更新。
TLS 1.3 是 TLS 很大的一步。它新增的特性中相当令人瞩目的两个,一个是 0-RTT,另一个就是随着 KeyShareEntry
的出现而变为现实的 ESNI (Encrypted SNI,后由 ECH (Encrypted Client Hello) 取代)草案。带上 ECH,这份草案目前已经有了十个版本(最新的在这里:draft-ietf-tls-esni-10),也受部分浏览器(Firefox 支持过 ESNI,现在支持 ECH;Chromium 跳过了 ESNI,ECH 支持在做了)以及部分服务商(CloudFlare 的许多网站支持 ESNI)的支持。
SNI (Server Name Indication) 主要用于同 IP 托管多个域名的情况。在这种情况下,客户端需要告知服务端其所访问的域名,服务端才能回复正确的证书,从而继续 TLS 握手过程。因此,虽然 TLS 使得用户的浏览内容和 HTTP 头都受到加密,第三方无法解密(如果你像 CNNIC 一样能用根证书做中间人攻击,当我没说),但在访问使用了 SNI 的网站时,客户端告知域名的信息需要以明文的形式传递。这是一个鸡生蛋、蛋生鸡的问题:没有域名就无法发送证书,而没有证书就不能进行加密。此时,中间人便可以从 SNI 信息获取客户端所访问的域名,从而进行相应的处理(例如拦截)。这也是 SNI 封锁的原理。有了 ECH 的加持,HTTP 的整个过程就都被 TLS 等组件保护,变得全副武装。因此,也有人说 ECH 是加密浏览的最后一块拼图。
基于国家安全和网络主权原因,在某些国家和地区, ESNI 已经全部被封锁(不过 ECH 可能还没)。不过,不受此影响的用户可以继续往下看。
那 ESNI/ECH 的加密是怎么来的?
没有 SNI,就没有服务器证书,那 ESNI/ECH 考靠什么进行身份验证和加密呢?答案是 DNS。DoH (DNS over HTTPS) 和 DoT (DNS over TLS) 的广泛应用已经使 DNS 请求的机密性和完整性 (integrity) 得到了良好的保护。因此,在 DoH 和 DoT (想的话还可以带上 DNSSEC)下, DNS 可以被认为是安全和私密的。不过明文 DNS 也罢,草案表示,如果 DNS 都被控制了,那这里其它的加密手段也没有意义。近期的一个新草案 DNS SVCB 和 HTTPS RR (draft-ietf-dnsop-svcb-https-05
) 推出了一些基于 DNS 进行查询的扩展。ESNI 和 ECH 就利用了这些扩展,通过 DNS 查询得到的信息和服务器建立加密信道。这两个草案蛮复杂的,这里就不展开讲了。
上手 ESNI/ECH
配置 DNS over HTTPS
此段落只设计给想要开启 ESNI 的用户。ECH 可能不需要 DoH。
前文说到,为了实现 ESNI,浏览器需要一些 DNS 扩展。考虑到操作系统一般没有除了获取 IP 地址(getaddrinfo()
)之外的 DNS 相关 API,Firefox 另辟蹊径,通过其添加的 DNS over HTTPS 支持来实现自己需要的功能。因此,为了开启 ESNI,需要先启用 DNS over HTTPS。
这并不复杂。在设置页面(about:preferences
)搜索 DNS,点击「网络设置」一节的设置按钮,翻到最底下,就能看到 DNS over HTTPS 的设定。
![Enable DoH on Firefox](https://res.cloudinary.com/dwgvzwmqu/image/upload/blog5/2020-firefox-doh-ech-esni/enable-doh.png)
Enable DoH on Firefox
在这里,可以按照自己的喜好选择 DNS 服务提供商。如果对隐私有担忧,可以选择一些其它的 DoH 提供商,而不是那个位于美国的世界最大 MitM 公司。
开启 ESNI
Firefox 85 起用 ECH 替代了 ESNI,因此这条配置项可能已经从你使用的 Firefox 中移除。
在 about:config
搜索条目 network.security.esni.enabled
,将其设定改为 true
即可。
开启 ECH
ECH 尚未广泛部署。
在 about:config
搜索条目 network.dns.echconfig.enabled
和 network.dns.use_https_rr_as_altsvc
,将它们的设定改为 true
即可。
测试 ESNI
配置完成后(可能需要重新启动浏览器),可以访问 https://www.cloudflare.com/ssl/encrypted-sni/ ,按下 "Check My Browser" 按钮,就可以测试自己是否开启了 ESNI 了。
![Result of ESNI enabled](https://res.cloudinary.com/dwgvzwmqu/image/upload/blog5/2020-firefox-doh-ech-esni/cf-test.png)
Result of ESNI enabled
esnicheck 提供了一些支持 ESNI 的网站列表,也可以用来测试某个网站是否支持 ESNI。
常见问题
Cloudflare 提醒我 ESNI 未启用!
可能是你的 DNS over HTTPS 并没有生效,Firefox 还在使用普通的 DNS 请求方式。这种情况下 ECH 无法工作。
你可以尝试按照 Mozilla Wiki 的指示,在 about:config
中将 network.trr.mode
设置为 3
,即只使用 TRR(也就是我们的 DNS over HTTPS),强制 Firefox 使用 DoH,这样就能确保使用 ESNI 了。
我按上条开启了 DoH only,但有的网站无法访问了!
主要有两种情况:
- Firefox 默认不会接受通过 DoH 解析得来的本地地址结果1 2。对于这种情况,在
about:config
中将network.trr.allow-rfc1918
设置为true
即可。 - 如果你使用默认的 Cloudflare DNS,并且访问的是
archive.is
的话:包括 archive.is 在内的少数网站要求对其服务器 IP 进行查询的客户端支持 ECS 拓展,以提供最优化的解析结果,而 Cloudflare DNS 出于隐私原因故意不支持 ECS。两边无法调和,于是使用 Cloudflare DNS 的用户就无法访问这些站点了(除非更换 DNS 服务器)。