如何使用 ESNI 保护您的公共网站

你好 Habr,我叫 Ilya,在 Exness 的平台团队工作。 我们开发并实施产品开发团队使用的核心基础设施组件。

在这篇文章中,我想分享我在公共网站基础设施中实施加密SNI(ESNI)技术的经验。

如何使用 ESNI 保护您的公共网站

使用该技术将提高使用公共网站时的安全级别,并符合公司采用的内部安全标准。

首先,我想指出该技术尚未标准化,仍处于草案阶段,但 CloudFlare 和 Mozilla 已经支持它(在 草稿01)。 这激励我们进行这样的实验。

有些理论

埃斯尼 是 TLS 1.3 协议的扩展,允许在 TLS 握手“Client Hello”消息中进行 SNI 加密。 这是支持 ESNI 的 Client Hello 的样子(我们看到的是 ESNI,而不是通常的 SNI):

如何使用 ESNI 保护您的公共网站

 要使用 ESNI,您需要三个组件:

  • 域名系统; 
  • 客户支持;
  • 服务器端支持。

DNS

您需要添加两条 DNS 记录 – ATXT (TXT 记录包含客户端可以用来加密 SNI 的公钥) - 见下文。 此外,还必须有支持 卫生部 (DNS over HTTPS),因为可用的客户端(见下文)在没有 DoH 的情况下无法启用 ESNI 支持。 这是合乎逻辑的,因为 ESNI 意味着对我们正在访问的资源名称进行加密,也就是说,通过 UDP 访问 DNS 是没有意义的。 此外,使用 DNSSEC 允许您在这种情况下防范缓存中毒攻击。

目前可用 多家卫生部提供商, 他们之中:

CloudFlare的 美国 (检查我的浏览器→加密的SNI→了解更多)他们的服务器已经支持ESNI,也就是说,对于DNS中的CloudFlare服务器我们至少有两条记录 - A和TXT。 在下面的示例中,我们查询 Google DNS(通过 HTTPS): 

А 记录:

curl 'https://dns.google.com/resolve?name=www.cloudflare.com&type=A' 
-s -H 'accept: application/dns+json'
{
  "Status": 0,
  "TC": false,
  "RD": true,
  "RA": true,
  "AD": true,
  "CD": false,
  "Question": [
    {
      "name": "www.cloudflare.com.",
      "type": 1
    }
  ],
  "Answer": [
    {
      "name": "www.cloudflare.com.",
      "type": 1,
      "TTL": 257,
      "data": "104.17.210.9"
    },
    {
      "name": "www.cloudflare.com.",
      "type": 1,
      "TTL": 257,
      "data": "104.17.209.9"
    }
  ]
}

TXT 记录,根据模板生成请求 _esni.FQDN:

curl 'https://dns.google.com/resolve?name=_esni.www.cloudflare.com&type=TXT' 
-s -H 'accept: application/dns+json'
{
  "Status": 0,
  "TC": false,
  "RD": true,
  "RA": true,
  "AD": true,
  "CD": false,
  "Question": [
    {
    "name": "_esni.www.cloudflare.com.",
    "type": 16
    }
  ],
  "Answer": [
    {
    "name": "_esni.www.cloudflare.com.",
    "type": 16,
    "TTL": 1799,
    "data": ""/wEUgUKlACQAHQAg9SiAYQ9aUseUZr47HYHvF5jkt3aZ5802eAMJPhRz1QgAAhMBAQQAAAAAXtUmAAAAAABe3Q8AAAA=""
    }
  ],
  "Comment": "Response from 2400:cb00:2049:1::a29f:209."
}

因此,从 DNS 角度来看,我们应该使用 DoH(最好使用 DNSSEC)并添加两个条目。 

客户支持

如果我们谈论浏览器,那么现在 仅在 FireFox 中实现支持. 这是 以下是有关如何在 FireFox 中激活 ESNI 和 DoH 支持的说明。 配置浏览器后,我们应该看到如下内容:

如何使用 ESNI 保护您的公共网站

链接 检查浏览器。

当然,必须使用 TLS 1.3 来支持 ESNI,因为 ESNI 是 TLS 1.3 的扩展。

为了测试具有 ESNI 支持的后端,我们在 go, 但稍后会详细介绍。

服务器端支持

目前,nginx/apache 等 Web 服务器不支持 ESNI,因为它们通过 OpenSSL/BoringSSL 使用 TLS,而 OpenSSL/BoringSSL 并不正式支持 ESNI。

因此,我们决定创建自己的前端组件(ESNI 反向代理),它将支持 ESNI 的 TLS 1.3 终止,并将 HTTP(S) 流量代理到不支持 ESNI 的上游。 这使得该技术可以在现有的基础设施中使用,而无需更改主要组件 - 即使用不支持 ESNI 的当前 Web 服务器。 

为了清楚起见,这里有一个图表:

如何使用 ESNI 保护您的公共网站

我注意到代理被设计为能够在没有 ESNI 的情况下终止 TLS 连接,以支持没有 ESNI 的客户端。 此外,与上游的通信协议可以是 HTTP 或 HTTPS,且 TLS 版本低于 1.3(如果上游不支持 1.3)。 该方案提供了最大的灵活性。

ESNI 支持的实施 go 我们借用了 CloudFlare的。 我想立即指出,实现本身非常重要,因为它涉及标准库的更改 加密/tls 因此需要“修补” 组装前。

为了生成 ESNI 密钥,我们使用了 埃斯尼图尔 (也是 CloudFlare 的创意)。 这些密钥用于 SNI 加密/解密。
我们在 Linux(Debian、Alpine)和 MacOS 上使用 go 1.13 测试了构建。 

关于操作功能的一些说明

ESNI 反向代理提供 Prometheus 格式的指标,例如 rps、上游延迟和响应代码、失败/成功的 TLS 握手和 TLS 握手持续时间。 乍一看,这似乎足以评估代理如何处理流量。 

我们还在使用前进行了负载测试。 结果如下:

wrk -t50 -c1000 -d360s 'https://esni-rev-proxy.npw:443' --timeout 15s
Running 6m test @ https://esni-rev-proxy.npw:443
  50 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.77s     1.21s    7.20s    65.43%
    Req/Sec    13.78      8.84   140.00     83.70%
  206357 requests in 6.00m, 6.08GB read
Requests/sec:    573.07
Transfer/sec:     17.28MB 

我们进行了纯粹的定性负载测试,以比较使用 ESNI 反向代理和不使用 ESNI 反向代理的方案。 我们在本地“倒”流量,是为了消除中间组件的“干扰”。

因此,借助 ESNI 支持并从 HTTP 代理到上游,我们从一个实例获得了大约 550 rps,其中 ESNI 反向代理的平均 CPU/RAM 消耗如下:

  • 80% CPU 使用率(4 个 vCPU、4 GB RAM 主机、Linux)
  • 130 MB 内存 RSS

如何使用 ESNI 保护您的公共网站

作为比较,没有 TLS(HTTP 协议)终止的相同 nginx 上游的 RPS 约为 1100:

wrk -t50 -c1000 -d360s 'http://lb.npw:80' –-timeout 15s
Running 6m test @ http://lb.npw:80
  50 threads and 1000 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.11s     2.30s   15.00s    90.94%
    Req/Sec    23.25     13.55   282.00     79.25%
  393093 requests in 6.00m, 11.35GB read
  Socket errors: connect 0, read 0, write 0, timeout 9555
  Non-2xx or 3xx responses: 8111
Requests/sec:   1091.62
Transfer/sec:     32.27MB 

超时的存在表明资源不足(我们使用 4 个 vCPU、4 GB RAM 主机、Linux),而且实际上潜在的 RPS 更高(我们在更强大的资源上收到高达 2700 RPS 的数据)。

总之,我注意到 ESNI 技术看起来很有前途。 仍然有许多悬而未决的问题,例如,在 DNS 中存储公共 ESNI 密钥和轮换 ESNI 密钥的问题 - 这些问题正在积极讨论,最新版本的 ESNI 草案(在撰写本文时)已经发布 7.

来源: habr.com

添加评论