この記事で伝えること
ブラウザのアドレスバーに表示される「🔒」マーク、あの南京錠はHTTPSが使われているサインです。「暗号化されている」とはなんとなく知っていても、その内側でどんな処理が動いているかを説明できる人は意外と少ないのではないでしょうか。
この記事では、HTTPSを支えるTLS(Transport Layer Security)の仕組みを、鍵交換・証明書・ハンドシェイクの流れを中心にできるだけわかりやすく解説します。
HTTPとHTTPSの違い
まずシンプルに整理すると:
| 項目 | HTTP | HTTPS |
|---|---|---|
| 通信内容 | 平文(丸見え) | 暗号化済み |
| ポート番号 | 80 | 443 |
| セキュリティ | なし | TLSで保護 |
| 主な用途 | 開発環境など | 現代のほぼすべて |
HTTPは平文で通信するため、ネットワーク上の第三者に通信内容を盗み見られるリスクがあります(中間者攻撃)。これを防ぐのがHTTPS = HTTP over TLSです。
対称暗号と公開鍵暗号
TLSを理解するには、2種類の暗号方式を押さえる必要があります。
対称暗号(共通鍵暗号)
送信者と受信者が同じ鍵を持ち、暗号化・復号の両方に使う方式です。
平文 → [共通鍵で暗号化] → 暗号文 → [同じ鍵で復号] → 平文
処理が速い反面、「最初にどうやって鍵を共有するか」という問題があります(鍵配送問題)。
公開鍵暗号(非対称暗号)
公開鍵と秘密鍵のペアを使います。公開鍵で暗号化したものは、対応する秘密鍵でしか復号できません。
平文 → [公開鍵で暗号化] → 暗号文 → [秘密鍵で復号] → 平文
鍵配送問題は解決できますが、計算コストが高いため大量データの暗号化には向きません。
TLSはこの両者を組み合わせています。
公開鍵暗号で「共通鍵を安全に共有」し、実際の通信は高速な共通鍵暗号で行う、というのがTLSの基本的な考え方です。
TLSハンドシェイクの流れ
実際の接続確立(ハンドシェイク)をシーケンス図で見てみましょう。
各ステップの解説
1. ClientHello
クライアントが「こんにちは、こんな暗号が使えます」と申告します。使えるTLSバージョン、対応する暗号スイートの一覧、乱数(クライアントランダム)を送ります。
2. ServerHello
サーバーが「この暗号方式を使いましょう」と回答し、自分の乱数(サーバーランダム)を返します。
3. Certificate(証明書の送付)
サーバーがSSL/TLS証明書を送ります。証明書には:
- サーバーの公開鍵
- ドメイン名
- 発行者(CA:認証局)の署名
が含まれています。
4. 証明書の検証
クライアントは、証明書がブラウザに組み込まれた信頼できるCAによって署名されているかを検証します。これにより「本物のサーバーと通信している」ことを確認できます。
5. ClientKeyExchange
クライアントがプレマスターシークレット(乱数)を生成し、サーバーの公開鍵で暗号化して送ります。サーバーは自分の秘密鍵で復号します。
この時点でクライアントとサーバーは同じ3つの値(クライアントランダム・サーバーランダム・プレマスターシークレット)を持っています。この3つを組み合わせてセッション鍵(共通鍵)を生成します。
6. ChangeCipherSpec & Finished
「以降は暗号化通信に切り替えます」という宣言と、ハンドシェイクが改ざんされていないことを確認するFinishedメッセージを送り合います。
証明書チェーンとCA
サーバー証明書の信頼性を保証するのが**CA(Certificate Authority:認証局)**です。
ルートCA(最上位の信頼の起点)
└─ 中間CA(ルートCAが署名)
└─ サーバー証明書(中間CAが署名)
ブラウザには「信頼できるルートCA」の一覧があらかじめ組み込まれています。サーバー証明書がそこに辿り着けるチェーンを持っていれば、信頼済みとみなされます。
チェーンが途切れると「この接続は安全ではありません」という警告が表示されます。
TLS 1.3 での変更点
現在の最新版TLS 1.3では、ハンドシェイクが大幅に効率化されています。
- ラウンドトリップ数が削減(1-RTTで接続確立)
- 古くて安全でない暗号スイートが廃止
- 0-RTT(ゼロラウンドトリップ)でリピート接続を高速化
TLS 1.2以前は2往復必要だったハンドシェイクが、TLS 1.3では1往復で済むようになりました。
筆者の考え・所感
TLSを学んで面白いと思ったのは、「公開鍵暗号と共通鍵暗号のいいとこ取り」という設計の巧みさです。公開鍵暗号だけで全通信を暗号化するのはコストが高すぎる。でも共通鍵だけだと鍵を安全に共有できない。その制約を両者の組み合わせで解決しているのは、実にエレガントだと感じます。
また、証明書チェーンの仕組みも「信頼の連鎖」として非常に直感的です。ゼロから知らない相手を信頼するのではなく、すでに信頼している誰か(CA)が保証してくれている人を信頼する。これは現実社会の信頼構築とも似ていて、面白いと思います。
開発中に curl -k でSSL検証を無効にして叩いたり、自己署名証明書でローカル開発するとき、今はちゃんと「このフラグがどの検証ステップをスキップしているか」をイメージできるようになりました。基礎を理解すると、デバッグの解像度が上がるのを実感しています。
まとめ
- HTTPS = HTTP + TLS。TLSが通信を暗号化・認証する
- TLSは公開鍵暗号で鍵交換し、実通信は共通鍵暗号で行う
- 証明書チェーンでサーバーの正当性を確認し、中間者攻撃を防ぐ
- ハンドシェイクの流れを理解すると、証明書エラーやSSL関連のデバッグがスムーズになる