加密通信的最后一公里 - ECH

熟悉我的人都知道,我是蛮喜欢 Cloudflare 这家厂商的,说他们是赛博慈善家绝不夸张。今天主要想讲一讲 CF 在大概 2021 年发起的一项提案: https://datatracker.ietf.org/doc/draft-ietf-tls-esni/ 也就是 Encrypted Clien

熟悉我的人都知道,我是蛮喜欢 Cloudflare 这家厂商的,说他们是赛博慈善家绝不夸张。今天主要想讲一讲 CF 在大概 2021 年发起的一项提案:

https://datatracker.ietf.org/doc/draft-ietf-tls-esni/

也就是 Encrypted Client Hello,算是 ESNI 的后继者吧。

TLS 与 DH 算法

首先我们需要理解,TLS(安全传输层协议)位于 TCP 与应用层之间。HTTPS 相对于 HTTP 来说,协议本身没什么改变,而是在 TCP 与 HTTP 间添加了一层 TLS 用作加密以保证信息安全。

TLS 同时使用对称和非对称做加密,大家都知道非对称速度慢,对称速度快,那 TLS1.3 为保证安全性同时兼顾性能先使用 Diffie–Hellman 交换密钥,DH 大概套路是客户端和服务器都生成一对公私钥,再把各自公钥发送给对方,双方得到对方的公钥后,用数字签名确保公钥没有被篡改,然后与自己的私钥结合,就可以计算得出相同的密钥。DH 算法就不细说了,它的核心是基于有限域中计算离散对数的困难性设计出来的,而离散对数的求解是数学界公认的无解难题,想了解原理的可以看下图(我特地找到了本科上课时的课本,然后拍照下来...这上面解释的虽然很学术,但仔细看也是很容易理解的):

通信双方协商完毕获得加密的密钥后,接下来的数据就都通过协商产生的密钥做对称加密。

为什么 TLS 1.3 抛弃了 RSA 交换密钥

RSA 不是前向安全的,通俗的讲,前向安全意思是如果攻击者保存了之前加密会话的流量,并设法获取到了私钥,他就能解密全部流量。但是对于 DH 算法来说,只要每次通信生成新的密钥对,那么解密的密钥每次通信都会不同。

TLS 中还有什么安全问题?

以 TLS1.3 的握手流程为例,分析这里面存在哪些不安全的地方:

  1. 客户端Hello(ClientHello)

    • 客户端发送“ClientHello”消息,包括所支持的最高TLS协议版本、客户端生成的随机数、可接受的密码套件列表、压缩方法,以及其他扩展(如支持的群组、预共享密钥(PSK)标识符等)。

  2. 服务端Hello(ServerHello)

    • 服务端选择一个与客户端共同支持的协议版本和一个密码套件。服务端也生成一个随机数。

    • 服务端发送“ServerHello”消息,包括选定的协议版本、服务端随机数、选定的密码套件,以及其他必要的扩展。

  3. 服务端参数和证书

    • 服务端发送其数字证书,以便客户端可以验证服务端的身份。

    • 如果需要客户端证书(双向TLS),服务端将请求客户端证书。

    • 服务端可能还会发送一些额外的密钥交换信息和证书验证信息,如数字签名。

  4. 服务端完成(Server Finished)

    • 服务端发送“Finished”消息,该消息包含前面所有消息的加密验证代码(验证数据),以确认消息的完整性和真实性。

  5. 客户端参数和证书

    • 客户端验证服务端的证书和签名,确认服务端的身份。

    • 客户端发送包含预主密钥材料的密钥共享信息(如果使用密钥交换)。

    • 如有需要,客户端也发送自己的证书。

  6. 客户端完成(Client Finished)

    • 客户端发送“Finished”消息,同样包含前面所有消息的加密验证代码。

  7. 主密钥的派生

    • 在双方发送和接收“Finished”消息之后,双方利用之前交换的随机数和预主密钥材料,利用密钥派生函数(KDF)生成会话密钥。

  8. 加密通信

    • 握手完成后,所有后续的通信都使用派生的会话密钥进行加密。

缺陷

先说 SNI(Server Name Indication):

许多 Web 服务器(单个 IP)会托管多个网站,并且可能每个网站都有自己的 TLS 证书。如果服务器向客户端显示错误的证书,客户端是无法安全连接到网站的;SNI 告诉 Web 服务器在客户端与服务器之间的连接开始时用哪个 TLS 证书,算是 TLS 协议的补充吧。

但是,TLS 握手中的第一条消息"ClientHello"中,客户端会要求查看 Web 服务器的 TLS 证书,服务器也会发送给客户端,可是只有在使用 SNI 成功完成 TLS 握手后,才能进行加密啊!

看起来好像是个死循环了,那怎么办?只能不加密 SNI 咯。

PS:不加密 SNI 会引发很多问题,例如网络过滤、监控 or 审查,也就是说通过 SNI 有人可以知道你在访问 TG PornHub or X 哦~

ESNI 如何解决 SNI 不加密的问题呢?

Firefox 和 CF 在18年就支持了,这个技术就不细说了,否则文章太长了,大致方案就是使用公钥加密 SNI,首先在DNS 记录中添加一个服务端公钥,当客户端查找到服务器地址时,同时也能找到该服务端的公钥。然后,客户端使用公钥来加密 SNI 记录,只有服务端才能解密。

有了 ESNI 就够了吗?

想太多了,我们的链路还有一环啊:DNS 查询是明文啊,用来 ESNI 确实是不能从 TLS 握手时看到你访问量啥,但你总要查 DNS 吧!那怎么办呢?继续打补丁!基于 TLS 的 DNS(DoT)、基于 HTTPS 的 DNS(DoH) 和 DNSSEC。

前两个方法是使用 TLS 加密 DNS 查询。DNSSEC 确认 DNS 记录真实并来自合法的 DNS 服务器,而非来自冒充 DNS 服务器。

那 ECH 的优势呢?

先说说 ESNI DNSSEC DoT DoH的局限性:

  1. ESNI 的局限性

    • ESNI并非广泛支持:ESNI的支持不是特别好;

    • ESNI 只加密SNI字段:ESNI仅仅加密了SNI字段,而整个ClientHello消息中还包含其他可能泄露用户隐私的元素,如密码套件、TLS版本等。这些信息可以被用来推断用户的浏览习惯或设备类型;

  2. DNSSEC、DoT、DoH 的局限性

    • 这些技术主要针对DNS查询和响应的安全性:DNSSEC确保DNS响应的真实性和完整性,防止DNS欺骗。DoT和DoH加密DNS查询,保护查询内容不被窃听;

    • DNS层面的加密不影响TLS握手:即使DNS查询被加密,TLS握手时发送的ClientHello消息仍然可以暴露用户信息。例如,即使你通过DoH安全地解析了一个网站的IP地址,TLS握手过程中明文的ClientHello信息还是可以让中间人知道你正在尝试连接到哪个网站;

  3. ECH 的优势

    • 全面加密ClientHello消息:ECH不仅加密SNI,还加密整个ClientHello消息的其他部分。这意味着除了服务器名,其他可能泄露信息的元素(如TLS版本和密码套件偏好)也被保护,防止被外部观察者分析;

    • 增强隐私保护:通过 ECH,即使是能够观察到你网络流量的本地网络运营商或某些"合法"监视者也无法确定你正在访问哪个具体网站,因为整个 ClientHello 包括服务器名都被加密;

ECH 怎么做到的呢?

使用ECH时,ClientHello消息部分被分为两个单独的消息:一个内部部分和一个外部部分。外部部分包含非敏感信息,如使用哪些加密算法和TLS版本。它还包括一个“外部SNI”。内部部分被加密,并包含一个“内部SNI”。外部SNI是一个通用名称,CF的服务中 cloudflare-ech.com 就是所有托管在 Cloudflare 网站上共享的SNI。

由于Cloudflare控制该域名和证书,所以能够为该服务器名称协商TLS握手。内部SNI包含用户试图访问的实际服务器名称。这里是公钥加密过后的数据,只有 Cloudflare 能够读取。一旦握手完成,网页像加载任何其他通过TLS加载的网站一样正常加载。

在实践中,这意味着任何试图确定您正在访问哪个网站的中间人将只会看到正常的TLS握手,每当您 Cloudflare 上启用 ECH 的网站时,服务器名称看起来是一样的,都是在尝试加载 cloudflare-ech.com 的网站,而不是你真实的网站。这也解决了保护用户隐私的最后一公里问题:用户不喜欢中间人看到他们正在访问哪些网站。

如何在服务端启用:

在 CF 的 Dashboard 中开启就好了:

检查客户端有没有开启 ECH:

https://www.cloudflare.com/zh-cn/ssl/encrypted-sni

LICENSED UNDER CC BY-NC-SA 4.0
Comment