Dev Study
← Webを支えるソフトウェア
レッスン 7 / 13·約 8 分·第3期 Webを支えるソフトウェア

TLS終端 — どこで暗号を解くのか

リクエストがアプリケーションに届くまで
  1. ブラウザURL入力
  2. DNS名前→IP
  3. ルータ経路選択
  4. ロードバランサ振り分け今ここ
  5. Nginx受け口
  6. アプリ処理
  7. DB保存

第29〜32週で配り先と設定を見ました。今週はその手前、暗号をどこで解くかという配置の判断です。

まず結論

TLSを終端した場所が、TLSのエンドポイントです。RFC 8446 が保証するのはその区間までで、内側をどう守るかはRFCの外側の設計判断です。

ECH を使わない接続なら、LBは復号せずにホスト名で振り分けられます。ClientHello が鍵確立より前に送られるからです。ECH(RFC 9849)を使う接続では本来のホスト名は暗号化され、LBに見えるのは外側の ClientHello の値だけになります。

? 読む前に予測

「TLS 1.3 ではハンドシェイクが暗号化されるので、LBはSNI(接続先ホスト名)を見て振り分けることができない」——この説明は正しいでしょうか。

当てることが目的ではありません。外した予測ほど記憶に残るので、直感で選んでください。

抽象原理

終端とは、エンドポイントになること

暗号化された通信は、どこかで必ず復号されます。その場所がTLSの終端点です。

終端をLBに置けば、LBから先のアプリケーションへは復号済みのデータが流れます。アプリまで終端しなければ、LBは中身を読めません。どちらを選ぶかで、暗号が守っている区間が変わります。

✓ ここまでの確認

「LBでTLSを終端し、内側は平文にする」構成について、RFC 8446 はどう述べていますか。

具体実物

なぜLBは復号せずに振り分けられるのか

TLSを終端しないまま、ホスト名で配り先を選ぶ構成があります。復号していないのに、なぜ宛先ホスト名が読めるのでしょうか。

RFC 8446 の記述を2つ並べると導けます。

RFC 8446 の記述(逐語)と、そこから導けること表
§2 "Everything after this phase is encrypted."
(鍵交換フェーズより後はすべて暗号化される)
§1.2 "All handshake messages after the ServerHello are now encrypted."
(ServerHello より後のハンドシェイクは暗号化される)
導かれること: ClientHello はこの「後」に入らない = 暗号化されない

server_name は ClientHello に載る拡張です。ClientHello は鍵が確立する前に送られるので、暗号化されません。だからLBは復号せずに覗くだけでホスト名が読め、パススルーのまま振り分けられます。 ただしこれは ECH を使わない接続の話です。ECH(RFC 9849)では本来の ClientHello が暗号化され、外側の ClientHello の server_name にはクライアントが最初に接続するサーバ(client-facing server)の名前 public_nameを入れることが SHOULD とされます。RFC 9849 §8.2 も「SNIに依存するサーバ配置——たとえば負荷分散——は、更新なしでは正しく動かなくなるおそれがある」と書いています。

✓ ここまでの確認

SNI(server_name 拡張)を定義しているのはどの文書ですか。

⇄ 2つを見比べる
具体例 A

LBで終端する構成

LBが復号するので、LBはパスやヘッダを見て振り分けたりキャッシュしたりできます。代わりにLBから先は平文になり、その区間はTLSの保証の外です。

保護される区間表
クライアント === TLS ===> LB ---平文---> アプリ
↑ここで保証が切れる
具体例 B

終端しない(パススルー)構成

LBは復号しないので中身を読めず、振り分けに使えるのは ClientHello に載る server_name 程度です(ECH を使う接続では外側の ClientHello の値だけ)。代わりに暗号はアプリまで届きます。

保護される区間表
クライアント ====== TLS ======> アプリ
LB は ClientHello を覗くだけ

2つの構成に共通する判断の軸は何でしょうか。そして、その軸のどこに線を引くかは何が決めるのでしょうか。

「途中の機械に何をさせたいか」と「どの区間を守りたいか」を同時に満たせるかを考えてください。

この章のまとめ

  • 終端した場所がTLSのエンドポイント。 RFC 8446 の保証はその区間までで、内側はRFCの外側の設計判断。
  • RFC 8446 は終端の位置を推奨も非推奨もしていない。
  • ECH を使わない接続でLBが復号せず振り分けられるのは、ClientHello が鍵確立より前に送られるから。server_name はそこに載る。ECH(RFC 9849)を使うと本来の server_name は暗号化される。
  • 「SNIは平文」と逐語で書いた文は RFC 6066・RFC 8446 には無い。 RFC 8446 からは §2 と §1.2 の構造的帰結として述べ、明記した文としては RFC 9849 §1 を引く。
  • SNIの定義は RFC 6066 §3。 RFC 8446 は参照しているだけ。
  • 0-RTT はPSKが前提で初回接続では使えず、接続をまたぐリプレイは防げない(§2.3)。

自分の現場で確かめる

読んだだけでは身につきません。手元の環境で実際に見てみてください。

環境:

理解度チェック

読んだ直後は「分かった」と感じやすいものです。実際に解いて確かめてください。

問題 1 / 2正解: 0

設計書に「LBでTLS終端するので、経路全体が暗号化され安全です」とありました。どう指摘しますか。

用語集(4語)
TLS終端
暗号化された通信を復号し、TLSのエンドポイントとして振る舞うこと。終端した場所より先はTLSの保証の外になる。
SNI(server_name 拡張)
接続先のホスト名をサーバへ伝える拡張。定義は RFC 6066 §3。RFC 8446 は参照しているだけで定義していない。
ClientHello
ハンドシェイクの最初のメッセージ。鍵の確立より前に送られるため暗号化されない。server_name はここに載る。ECH(RFC 9849)では本来の ClientHello を暗号化し、外側の ClientHello に入れて送る。
0-RTT(early data)
PSKを使い最初のフライトでデータを送るモード。前方秘匿性が無く、接続をまたぐリプレイを防げない(RFC 8446 §2.3)。