ESNI 功能简要概述

0. 背景

目前访问网站时,基本上都会采用TLS加密的方式,用于保护数据的安全性。但是为了例如 CDN 等需要在同一个机器上部署多个网站的服务,那么 SNI(Server Name Indication)将会被使用。相关流程如下图所示

传统HTTPS访问网站流程

可以明确的看到 SNI 是明文传输的。这样不怀好意的人就可以通过监听 SNI 来获取用户访问了什么网站。

1. 解决方案

1.1 思路1:不发送SNI

既然SNI是明文传输的,那么不发送 SNI 似乎就可以解决这个问题。事实上,确实有项目做到了这一点,例如revolter-firefox。这个项目可以正常访问部分网站。

但正如前文所说,如果一个服务器上部署了多个网站,那么服务端需要根据 SNI 来选择对应的网站。如果不发送 SNI,那么服务端就无法知道用户想要访问哪个网站,进而无法正确响应证书。

1.2 思路2:加密SNI

既然 SNI 是明文传输的,那么我们可以对 SNI 进行加密,这样就可以解决这个问题。这就是 ESNI(Encrypted SNI)的思路。

2. ESNI 工作原理

首先我们肯定会优先想到使用网站证书对 SNI 进行加密。但很可惜,在未收到 SNI 的条件下,服务端根本无法知道用户想要访问哪个网站,进而无法正确响应证书用于加密 SNI。

这就形成了一个悖论:服务端需要 SNI 来选择正确的证书提供给客户端,但是传输 SNI 需要服务端先提供客户端正确的证书。

破局方法就是与很多技术相近,即使用DNS

服务器在已知的DNS记录上发布一个公钥,客户端可以在连接之前获取该公钥。而后客户端使用该公钥对 SNI 进行加密,然后发送给服务器。服务器解密获得 SNI,然后选择正确的证书提供给客户端。

这样就解决了悖论,同时也解决了 SNI 明文传输的问题。

ESNI工作原理

3. 新的问题

这样会有什么问题?在查询对方服务器 DNS 记录的时候,由于 DNS 请求是明文传输的,那么就会暴露用户访问的网站。

为了解决这个问题,可以使用DNS over HTTPS(DoH)或者DNS over TLS(DoT)来加密 DNS 请求。

4. 进阶

TLS的ClientHello还有很多可能暴露信息的地方,因此考虑将整个ClientHello都加密,这就是 ECH(Encrypted Client Hello)。相关内容可以参考这篇文章

5. 参考


ESNI 功能简要概述
https://nacldragon.top/2025/ESNI/
作者
NaCl
发布于
2025年1月10日
许可协议