DIVE

Part 5: ネットワーク・SRE

第 14 章

TLS 1.3 — 盗聴される道で、なぜ秘密を守れるのか

前章で、TCPは信頼できない経路の上に信頼できる通信を築いた。だが、その通信は丸見えだった。パケットは無数のルーターを経由する。その途中で誰かが覗けば、あなたのパスワードもクレジットカード番号も、平文で読めてしまう。

ブラウザのURL欄にある錠前アイコン(HTTPS)は、この盗聴を防ぐ。だがここには、一見不可能な難題がある。盗聴されている通信路で、初対面のサーバーと、どうやって「二人だけの秘密の鍵」を共有するのか。 鍵そのものを送れば、盗聴者にも鍵が渡ってしまうのに。この章で、その魔法——TLS——を解く。


二つの暗号方式 — 歴史の必然

暗号には大きく二種類ある。まずその違いを押さえよう。

共通鍵暗号(対称鍵)は、暗号化と復号に同じ鍵を使う。速くて効率的だが、致命的な問題がある。どうやって相手に鍵を渡すのか。鍵を通信路で送れば、盗聴者にも鍵が渡る。かといって事前に会って手渡しするのは、地球の裏側のサーバーには不可能だ。これが鍵配送問題だ。

公開鍵暗号(非対称鍵)は、この問題を解く革命だった。ペアになった2つの鍵を使う。

公開鍵で暗号化→秘密鍵でのみ復号可能\text{公開鍵で暗号化} \xrightarrow{\quad} \text{秘密鍵でのみ復号可能}

公開鍵をばら撒いても、それで暗号化されたものは秘密鍵の持ち主しか読めない。「南京錠だけを配り、その鍵は自分だけが持つ」イメージだ。誰でも施錠(暗号化)できるが、開錠(復号)できるのは鍵の持ち主だけ。ただし公開鍵暗号は計算が重い。そこで実際のTLSは、両者を組み合わせる。


厨房のアナロジー — 鍵付きの受け渡しボックス

取引先と、レシピ(秘密の情報)をやり取りしたいとする。だが配達経路の途中に、内容を盗み見る者がいるかもしれない。

賢い方法はこうだ。まず取引先が、開いた状態の南京錠(公開鍵)だけを送ってくる。鍵本体(秘密鍵)は取引先が握ったままだ。あなたはレシピを箱に入れ、その南京錠で施錠して送り返す。施錠した箱は、途中で誰が奪っても開けられない。鍵を持つ取引先だけが開けられる。

そして本命はここからだ。この安全な箱を使って、あなたと取引先だけが知る「今日の合言葉(共通鍵)」を共有する。以降のやり取りは、軽くて速い合言葉方式(共通鍵暗号)で行う。「重い公開鍵は最初の鍵共有だけに使い、本番のデータは軽い共通鍵で」——これがTLSの基本戦略だ。

私が飲食店で機密のレシピや原価表を扱ったとき、鍵付きのボックスで受け渡しした経験に近い。中身そのものより、「鍵をどう安全に共有するか」が全ての要だった。


鍵交換 — 盗聴されても秘密を作る魔法

TLS 1.3の核心は、盗聴されている通信路で、二人だけの共通鍵を合成することだ。これを可能にするのがDiffie-Hellman鍵交換(DH)という、数学の美しいアイデアだ。

直感を「色の混合」で掴もう。混ぜた色から元の色を分離するのは極めて難しい、という一方向性を利用する。

アリス                    公開でやり取り            ボブ
  秘密の色 a                                        秘密の色 b
     │        共通の色(公開) を両者が知っている          │
     ▼                                              ▼
  共通+a を混ぜる ──────  送信(盗聴されてもOK)  ────▶ 受け取る
  受け取る       ◀────  送信(盗聴されてもOK)  ──────  共通+b を混ぜる
     │                                              │
     ▼                                              ▼
  (共通+b) に a を足す                        (共通+a) に b を足す
     └────────────┐              ┌───────────────┘
                  ▼              ▼
              両者とも「共通+a+b」という同じ色に到達!
              盗聴者は a も b も知らないので、この色を作れない

数学的には、大きな素数 pp と生成元 gg を公開し、各自が秘密の数 aa, bb を持つ。やり取りするのは ga mod pg^a \bmod p と gb mod pg^b \bmod p だけ。すると双方が同じ共通鍵に到達する:

(ga)b mod p=(gb)a mod p=gab mod p(g^a)^b \bmod p = (g^b)^a \bmod p = g^{ab} \bmod p

盗聴者は gag^a と gbg^b を見られるが、そこから aa や bb を逆算する(離散対数問題)のは、鍵が十分大きければ現実的な時間では解けない。だから盗聴者だけが gabg^{ab} を作れない。公開の場で、二人だけの秘密が生まれる。これが錠前アイコンの数学的な心臓部だ。


証明書 — 「本物の相手」だと証明する

鍵交換だけでは、まだ穴がある。あなたが鍵交換している相手は、本当に目的のサーバーか? 途中で攻撃者が「私が銀行です」と成りすまし、あなたと攻撃者、攻撃者と銀行で別々に鍵交換したら、通信は暗号化されていても攻撃者に筒抜けだ(中間者攻撃, MITM)。

これを防ぐのがサーバー証明書と、その裏にある公開鍵基盤(PKI)だ。

信頼の連鎖はこうなっている。認証局(CA)という、社会的に信頼された第三者が、「この公開鍵は確かに example.com のものだ」とデジタル署名して保証する。ブラウザは、あらかじめ信頼するCAの一覧(ルート証明書)を持っている。

信頼の連鎖(証明書チェーン):
  ルートCA(ブラウザが最初から信頼)
     │ 署名
     ▼
  中間CA
     │ 署名
     ▼
  example.com のサーバー証明書(公開鍵を含む)
     │
     ▼
  ブラウザ: チェーンを辿り、信頼するルートCAに行き着けば「本物」と判定 ✓

デジタル署名は、公開鍵暗号を逆向きに使う。CAは自分の秘密鍵で署名し、誰もがCAの公開鍵で「確かにこのCAが署名した」と検証できる。秘密鍵を持つCAにしか作れない署名だから、偽造できない。「証明書エラー」の警告は、この信頼の連鎖が途切れた(自己署名、期限切れ、ドメイン不一致など)ときに出る。


TLS 1.3ハンドシェイク — 速さと安全の両立

TLS 1.3(2018年標準化)は、これらを組み合わせつつ、接続の高速化を実現した。旧来のTLS 1.2が2往復(2-RTT)を要したのに対し、1-RTTで暗号通信を始められる。

クライアント                                サーバー
    │                                          │
    │─ ClientHello ───────────────────────────▶│
    │  + 鍵交換パラメータ(g^a)                    │  ①いきなり鍵材料を送る
    │  + 対応する暗号方式の候補                    │
    │                                          │
    │◀──────────── ServerHello ────────────────│
    │      + 鍵交換パラメータ(g^b)                │  ②鍵材料 + 証明書
    │      + サーバー証明書                       │
    │      + {以降このデータは暗号化}              │
    │                                          │
    │  この時点で両者とも共通鍵 g^(ab) を計算完了   │
    │═══════ 1-RTTで暗号化データ通信開始 ════════│

TLS 1.3は、安全性の低い古い暗号方式(RSA鍵交換など)をきっぱり廃止し、選択肢を安全なものだけに絞った。「設定を間違えて弱い暗号を選ぶ」余地を設計から消したのだ。第13章のTCPハンドシェイクの上に、このTLSハンドシェイクが乗る。「HTTPSの最初のアクセスが少し待たされる」のは、この二段構えの握手のためだが、TLS 1.3の1-RTT化でそれも大きく短縮された。


前方秘匿性 — 未来の漏洩から過去を守る

TLS 1.3が必須としたもう一つの重要な性質が前方秘匿性(Forward Secrecy, PFS)だ。

想像してほしい。攻撃者が、あなたの暗号化通信をすべて記録しておく。そして何年も後、サーバーの秘密鍵を何らかの方法で盗んだとする。もし過去の通信がその秘密鍵で復号できてしまうなら、記録された過去の通信がすべて暴かれる。

前方秘匿性は、これを防ぐ。鍵交換のたびに使い捨ての一時的な鍵を生成し、セッション終了後は破棄する。だから、後でサーバーの長期秘密鍵が漏れても、過去の各セッションの共通鍵は復元できない。

長期秘密鍵の漏洩⇏過去の通信の解読\text{長期秘密鍵の漏洩} \not\Rightarrow \text{過去の通信の解読}

これはDiffie-Hellmanの一時鍵(ephemeral、ECDHEの “E”)によって実現される。TLS 1.3では、この前方秘匿性が必須になった。「今は解読できないから記録しておいて後で解く」という攻撃(harvest now, decrypt later)への、設計レベルの防御だ。


まとめ — 「おまじない」の消し方

  1. 鍵配送問題こそ本質:共通鍵は速いが「鍵をどう渡すか」が難しい。公開鍵暗号がこれを解いた
  2. Diffie-Hellman鍵交換:盗聴される公開の場で、二人だけの共通鍵を数学的に合成する(gab mod pg^{ab} \bmod p)
  3. 証明書とPKI:CAの署名で「本物の相手」を保証し、中間者による成りすましを防ぐ
  4. TLS 1.3は速く安全:1-RTTで暗号通信を開始し、弱い暗号方式を設計から排除した
  5. 前方秘匿性:使い捨ての鍵で、将来の鍵漏洩からも過去の通信を守る

「なぜ盗聴される通信路で秘密を守れるのか」「錠前アイコンは何を保証しているのか」——その答えは、公開鍵暗号と、信頼の連鎖という設計にあった。

これで通信は「信頼でき、かつ秘匿される」ようになった。だが、システムを複数のマシンに分散させると、新たな哲学的難問が現れる。「一貫性」と「可用性」は、両立しない。次章では、分散システムの根本原理——CAP定理と、あえて壊して学ぶカオスエンジニアリング——へ進む。


「完全な秘密とは、鍵を隠すことではない。鍵の作り方を、二人だけが知っていることだ。暗号技術の歴史は、『何を秘密にすべきか』を問い直し続けた歴史でもある。」