ESNI を使用して公開 Web サイトを保護する方法

こんにちは、Habr、私の名前はイリヤです。Exness のプラットフォーム チームで働いています。 当社は、製品開発チームが使用するコア インフラストラクチャ コンポーネントを開発および実装します。

この記事では、公開 Web サイトのインフラストラクチャに暗号化 SNI (ESNI) テクノロジーを実装した私の経験を共有したいと思います。

ESNI を使用して公開 Web サイトを保護する方法

このテクノロジーを使用すると、公開 Web サイトを操作する際のセキュリティ レベルが向上し、当社が採用する内部セキュリティ標準に準拠します。

まず第一に、このテクノロジーは標準化されておらず、まだドラフト段階にあることを指摘したいと思いますが、CloudFlare と Mozilla はすでにこのテクノロジーをサポートしています ( ドラフト01)。 これが私たちにこのような実験をする動機となりました。

いくつかの説

エスニ これは、TLS ハンドシェイク「Client Hello」メッセージでの SNI 暗号化を可能にする TLS 1.3 プロトコルの拡張機能です。 ESNI サポートを使用した Client Hello は次のようになります (通常の SNI の代わりに ESNI が表示されます)。

ESNI を使用して公開 Web サイトを保護する方法

 ESNI を使用するには、次の XNUMX つのコンポーネントが必要です。

  • DNS; 
  • クライアントサポート。
  • サーバー側のサポート。

DNS

XNUMX つの DNS レコードを追加する必要があります – ATXT (TXT レコードには、クライアントが SNI を暗号化できる公開キーが含まれています) - 以下を参照してください。 さらに、サポートがなければなりません しない (DNS over HTTPS) は、利用可能なクライアント (以下を参照) が DoH なしでは ESNI サポートを有効にしないためです。 ESNI はアクセスしているリソース名の暗号化を意味するため、これは論理的です。つまり、UDP 経由で DNS にアクセスすることは意味がありません。 さらに、用途は、 DNSSEC このシナリオでは、キャッシュポイズニング攻撃から保護できます。

現在利用可能 いくつかの DoH プロバイダー、 その中で:

CloudFlareの 宣言する (「ブラウザー」→「暗号化された SNI」→「詳細」を確認) サーバーがすでに ESNI をサポートしていること、つまり、DNS 内の CloudFlare サーバーには少なくとも XNUMX つのレコード (A と TXT) があることを確認します。 以下の例では、(HTTPS 経由で) Google DNS にクエリを実行します。 

А 記録:

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 とともに) を使用し、XNUMX つのエントリを追加する必要があります。 

顧客サポート

ブラウザについて話しているのであれば、現時点では サポートは FireFox でのみ実装されています. それは ここでは、FireFox で ESNI および DoH サポートをアクティブ化する方法について説明します。 ブラウザが設定されると、次のように表示されるはずです。

ESNI を使用して公開 Web サイトを保護する方法

リンク ブラウザを確認します。

もちろん、ESNI は TLS 1.3 の拡張機能であるため、ESNI をサポートするには TLS 1.3 を使用する必要があります。

ESNI サポートを備えたバックエンドをテストする目的で、クライアントを go, しかし、それについては後で詳しく説明します。

サーバー側のサポート

現在、nginx/apache などの Web サーバーは、ESNI を正式にサポートしていない OpenSSL/BoringSSL 経由で TLS と連携するため、ESNI はサポートされていません。

したがって、ESNI で TLS 1.3 終端をサポートし、ESNI をサポートしていないアップストリームへの HTTP(S) トラフィックをプロキシする独自のフロントエンド コンポーネント (ESNI リバース プロキシ) を作成することにしました。 これにより、主要コンポーネントを変更することなく、つまり ESNI をサポートしていない現在の Web サーバーを使用することなく、既存のインフラストラクチャでこのテクノロジーを使用できるようになります。 

わかりやすくするために、次の図を示します。

ESNI を使用して公開 Web サイトを保護する方法

プロキシは、ESNI なしでクライアントをサポートするために、ESNI なしで TLS 接続を終了できるように設計されていることに注意してください。 また、アップストリームとの通信プロトコルは、TLS バージョン 1.3 より前の HTTP または HTTPS のいずれかになります (アップストリームが 1.3 をサポートしていない場合)。 このスキームにより、最大限の柔軟性が得られます。

ESNI サポートの実装 go 私たちはから借りました CloudFlareの。 標準ライブラリの変更が含まれるため、実装自体は非常に簡単ではないことにすぐに注意してください。 暗号化/TLS したがって「パッチ」が必要です ゴルート 組み立て前。

ESNI キーの生成に使用しました エスニツール (これも CloudFlare の発案です)。 これらのキーは SNI 暗号化/復号化に使用されます。
Linux (Debian、Alpine) および MacOS 上で go 1.13 を使用してビルドをテストしました。 

操作上の特徴について一言

ESNI リバース プロキシは、rps、アップストリーム レイテンシと応答コード、TLS ハンドシェイクの失敗/成功、TLS ハンドシェイク時間などのメトリクスを Prometheus 形式で提供します。 一見すると、プロキシがトラフィックをどのように処理するかを評価するにはこれで十分であるように思えました。 

使用前に負荷テストも実施しました。 以下の結果:

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 サポートと HTTP からアップストリームへのプロキシを使用すると、ESNI リバース プロキシの平均 CPU/RAM 消費量で、550 つのインスタンスから約 XNUMX rps を受信しました。

  • 80% の CPU 使用率 (4 vCPU、4 GB RAM ホスト、Linux)
  • 130 MB メモリ RSS

ESNI を使用して公開 Web サイトを保護する方法

比較のために、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 テクノロジーは非常に有望であると言えます。 ESNI 公開キーを DNS に保存する問題や ESNI キーをローテーションする問題など、未解決の疑問がまだ多くあります。これらの問題は活発に議論されており、ESNI ドラフトの最新バージョン (執筆時点) はすでに作成されています。 7.

出所: habr.com

コメントを追加します