04. 暗号と TLS - HTTPS の中身
読了時間: 40-60分(移動中に分割して読むと丁度よい) 想定読者: 「URL に鍵マークが付いてるやつ、何が起きてるかぼんやり知りたい人」 ゴール: HTTPS の通信が「なぜ盗み見られないのか」を、数式ナシで人に説明できる 手は動かさない: スマホ片手に読むだけでOK
この記事で持って帰れること
- 共通鍵 / 公開鍵 / ハッシュの3つを、日常の例えで人に説明できる
- TLS ハンドシェイクの流れを、ステップごとに語れる
- 証明書チェーンの「信頼の連鎖」が腹落ちする
- Let’s Encrypt がなぜ世界を変えたか、過去の TLS 事件 (Heartbleed, DigiNotar) から何を学ぶか、を言語化できる
- 量子コンピュータが暗号に与える脅威と、PQC への移行をどう考えるか、視座を持てる
前回 (03_DNS) との繋がり
前回 DoH (DNS over HTTPS) の話に少しだけ触れた。DNS を暗号化するのに使うのが、まさに今回の TLS。DNS の仕組み (名前 → IP) があって初めて HTTPS への接続が始まる。今回は「接続が始まったあと、何が起きているか」の話。
大前提: なぜ「暗号」がインターネットの根幹なのか
あなたが今この記事をスマホで読んでいるとして、Wi-Fi の電波は周りの人にも届いている。喫茶店の Wi-Fi なら、隣のテーブルの人も同じ電波を受信できる。なのに、なぜあなたがネット銀行に入った時の口座残高は隣の人にバレないのか。なぜカード番号を入力しても抜かれないのか。
答えは「全部暗号化されているから」。
これがもし暗号化されていなかった時代を想像してほしい。実際、1990年代前半までインターネットはほぼ全部「平文(へいぶん)」だった。Wi-Fi に繋がっているだけで、近くの人があなたのメールパスワードを覗き見できた。だから当時、銀行はネットでお金を扱うことなんて怖くてできなかった。
HTTPS が当たり前になったのは、実はここ10年くらいの話。それまでは「ログイン画面だけ HTTPS」というサイトが普通だった。なぜ全ページ HTTPS にしなかったか? サーバーの計算負荷が重かったから。証明書が有料で年間数万円したから。設定が難しかったから。
それが今や、個人ブログでも全部 HTTPS。なぜそうなったか。誰がどうやって世界を変えたか。この記事はその話。
この記事の楽しみ方
数学が苦手でも全然大丈夫。「鍵」「箱」「印鑑」みたいな日常の例えで全部説明する。 一気に読まなくていい。電車で1セクション、待ち時間で1セクション、と分けて読めるサイズに切ってある。 「ふーん」で読み流していい。後でカリキュラム本編で TLS を実際に設定する時、「あ、あの記事で読んだやつだ」と思い出せれば勝ち。
第1章: 暗号の歴史 - シーザーから現代まで
1-1. 紀元前から人類は隠したかった
暗号の歴史は2000年以上ある。最古の有名な暗号は シーザー暗号。ローマ帝国の独裁官、ユリウス・カエサル(シーザー)が軍事通信で使ったとされる。
仕組みは死ぬほど単純で、「アルファベットを3文字ずらす」。
A → D
B → E
C → F
...
HELLO → KHOOR
これだけ。これだけなんだけど、当時の敵兵が「KHOOR」と書かれた紙を拾っても意味不明だった。なぜなら、そもそも「ずらして読む」という発想自体が珍しかったから。
シーザー暗号の本質
- 鍵: 「3」という数字(ずらす数)
- 暗号化: 平文の各文字を3つ後ろにずらす
- 復号: 受け取った文字を3つ前にずらす
重要なのは、送る側と受け取る側が「3」という秘密を共有している こと。この「秘密の共有」がすべての暗号の原点。
1-2. でもこれ、めっちゃ簡単に破れる
シーザー暗号は今では小学生でも破れる。なぜか。
- ずらす数は1〜25しかない(26通り全部試せば終わり)
- 英語には「E が一番よく出る」「TH が頻出」みたいな統計的偏りがある
- 短い文章でも「the」「and」がどこに対応するか見れば即バレ
この「文字の出現頻度を数える」攻撃を 頻度分析 と言う。9世紀のアラブの数学者アル=キンディーが体系化した。つまり、暗号を作る側 vs 破る側の戦いは1000年以上前から続いている。
1-3. 第二次世界大戦と「エニグマ」
時代は飛んで20世紀。第二次大戦中、ナチス・ドイツは エニグマ という機械式暗号機を使っていた。タイプライターみたいな見た目で、キーを叩くと電気回路で複雑にシャッフルされた文字が出てくる。
エニグマは当時「絶対に破れない」と言われていた。組み合わせの数が天文学的だったから。
これを破ったのが、イギリスの数学者 アラン・チューリング と彼のチーム。ブレッチリー・パークという秘密施設で、彼らは世界初の本格的な「コンピュータ」と呼べる機械(Bombe)を作り、エニグマを破った。
チューリングとコンピュータの誕生
アラン・チューリングは「現代コンピュータの父」と呼ばれる人物。今あなたがスマホでこの記事を読めているのは、彼が暗号を破るために計算機の理論を作ったから。
「コンピュータ・サイエンス」という学問は、実は 暗号を破るために生まれた。これがエンジニアの教養として大事な視点。今でも CPU の高速化要求は、機械学習以前は暗号処理がドライバの一つだった。
映画「イミテーション・ゲーム」(2014)で彼の物語が描かれている。バックエンドエンジニアなら一度は観たい。
1-4. 戦後 - DES と「対称暗号」の時代
戦後、コンピュータが普及し、米国政府は標準的な暗号方式を求めた。1977年に DES (Data Encryption Standard) が制定される。これは「鍵」を使って文字列を機械的にぐちゃぐちゃに変換する方式。
DES もシーザー暗号と本質は同じ。送る側と受け取る側が同じ鍵を共有する。これを 対称暗号 または 共通鍵暗号 と呼ぶ。
[送信者] --(鍵A)で暗号化--> 暗号文 --(鍵A)で復号--> [受信者]
DES はその後、コンピュータの性能向上で破られるようになり、2001年に AES (Advanced Encryption Standard) に置き換わった。AES は今でも世界中で使われている対称暗号の王様。あなたのスマホの中、Wi-Fi、ファイル暗号化、ほぼ全部 AES。
対称暗号の本質と限界
本質: 「同じ鍵」で暗号化と復号をする。速い、シンプル。
限界: 「同じ鍵」をどうやって安全に相手に渡すか。
例えば、あなたが東京で、相手がニューヨークにいる。鍵を郵送する? 途中で盗まれるかも。電話で伝える? 盗聴されるかも。これが暗号の世界で 「鍵配送問題」 と呼ばれる難題だった。
1970年代まで、この問題には誰も答えを持っていなかった。
↓ 対称暗号(共通鍵)と公開鍵暗号(非対称)の構造的な違い ↓
flowchart TB subgraph Sym["対称暗号(共通鍵)"] S1[送信者] -->|平文 + 鍵Aで暗号化| S2[暗号文] S2 -->|鍵Aで復号| S3[受信者] SK[鍵 A<br/>同じ鍵を共有] SK -.同じ鍵.-> S1 SK -.同じ鍵.-> S3 end subgraph Asym["公開鍵暗号(非対称)"] A1[送信者] -->|平文 + 受信者の公開鍵で暗号化| A2[暗号文] A2 -->|受信者の秘密鍵で復号| A3[受信者] PK[公開鍵<br/>世界中に配布OK] SK2[秘密鍵<br/>受信者のみ保持] PK -.暗号化に使う.-> A1 SK2 -.復号に使う.-> A3 end classDef sym fill:#ffe1e1,stroke:#333 classDef asym fill:#e1f5ff,stroke:#333 class S1,S2,S3,SK sym class A1,A2,A3,PK,SK2 asym
第2章: 公開鍵暗号という革命
2-1. 1976年、世界が変わった
1976年、スタンフォード大学の ホイットフィールド・ディフィー と マーティン・ヘルマン が「Diffie-Hellman 鍵交換」という論文を発表した。
これが、暗号の歴史で最大の革命。「鍵配送問題」をエレガントに解いた。
彼らのアイデアは「鍵を2つに分ければいいんじゃね?」というもの。
- 公開鍵 (Public Key): 世界中にバラまいてOKな鍵。電話帳に載せてもいい
- 秘密鍵 (Private Key): 自分しか知らない鍵。絶対に外に出さない
そして、不思議な性質を持つ仕組みを作った:
- 公開鍵で暗号化したものは、対応する秘密鍵でしか復号できない
- 秘密鍵で署名したものは、対応する公開鍵で検証できる
これを 公開鍵暗号 (Public Key Cryptography) または 非対称暗号 と呼ぶ。
「南京錠」の例えで理解する
公開鍵 = 開いた状態の南京錠。世界中の人に配ってOK 秘密鍵 = その南京錠の鍵。自分だけ持っている
誰かがあなたに秘密のメッセージを送りたい場合:
- その人はあなたの南京錠(公開鍵)を入手する
- メッセージを箱に入れて、南京錠でガチャンとロックする
- ロックされた箱を郵送する
- 受け取ったあなたは、自分の秘密鍵で南京錠を開けて中身を読む
途中で誰が箱を盗んでも、南京錠を開ける鍵を持ってないから開けられない。鍵を事前に共有する必要がない。これが革命の正体。
2-2. RSA - 公開鍵暗号の代表選手
Diffie-Hellman の翌年、1977年。MIT の3人の研究者、Rivest, Shamir, Adleman が、具体的に動く公開鍵暗号方式を発明した。彼らの頭文字を取って RSA と名付けられた。
RSA は「大きな素数の掛け算は簡単、でも素因数分解は超難しい」という数学的事実を利用する。例えば:
13 × 17 = 221← 暗算でできる221 = ? × ?← 知らないと結構難しい
これを何百桁の素数でやると、世界最速のコンピュータでも数千年かかる。これが RSA の安全性の根拠。
RSA の設計思想
「簡単な方向には進めるが、逆方向には絶対に戻れない計算」のことを 一方向関数 (one-way function) と呼ぶ。
暗号は基本的にこの一方向関数で出来ている。「掛け算は簡単、素因数分解は難しい」「離散対数問題」「楕円曲線上の問題」など、種類はいくつかあるが、全部「片方向だけ簡単」という性質を使っている。
RSA の特許は2000年に失効した。それまで RSA は商用利用に金がかかった。これが OSS の暗号ライブラリが爆発的に普及した要因の一つ。
2-3. 楕円曲線暗号 (ECC) の台頭
RSA は今でも現役だが、最近は 楕円曲線暗号 (Elliptic Curve Cryptography, ECC) が主流になりつつある。
理由は単純で、同じ強度なら鍵が短くて済むから。
| 方式 | 安全性が同じくらいの鍵長 |
|---|---|
| RSA | 3072 bit |
| ECC | 256 bit |
鍵が短い = 計算が速い = スマホでもサクサク。だから現代の TLS は ECC を好んで使う。
ECC の仕組みをふんわり理解
楕円曲線というのは数学の曲線の一種で、「曲線上の点を足し算する」という変な演算ができる。これを使うと、「ある点を N 回足した結果から、N を逆算するのが超難しい」という一方向関数が作れる。
詳しい数学は理解しなくていい。「RSA は素数の掛け算、ECC は楕円曲線の点の足し算。両方とも『片方向だけ簡単』を使ってる」と覚えればOK。
2-4. Diffie-Hellman - 「鍵交換」専用の魔法
Diffie-Hellman (DH) は、公開鍵暗号の元祖だが、ちょっと変わった使われ方をしている。「2人が公開の場で会話して、共通の秘密の鍵を作る」 ことに特化している。
イメージで言うと:
- アリスとボブは公開の場で雑談する(全部盗聴されてもOK)
- その雑談の末、2人は同じ秘密の数字を頭の中で導き出す
- 盗聴していた第三者は、その秘密の数字を導き出せない
これがなぜ可能なのか、ふんわり例えると:
絵の具で例える Diffie-Hellman
- アリスとボブは公開で「黄色の絵の具を使う」と決める
- アリスは秘密に「赤」を選び、黄色 + 赤 = オレンジ を作ってボブに送る
- ボブは秘密に「青」を選び、黄色 + 青 = 緑 を作ってアリスに送る
- アリスは届いた緑に自分の赤を混ぜる: 緑 + 赤 = 茶色
- ボブは届いたオレンジに自分の青を混ぜる: オレンジ + 青 = 茶色
- 2人は同じ「茶色」という共通の秘密に到達した
盗聴者は「黄色」「オレンジ」「緑」を見られるが、そこから「茶色」を作るには、アリスの赤かボブの青を知る必要がある。絵の具を「分離する」のはほぼ不可能(一方向関数)。
実際は数学的にもっと高度な「指数の掛け算」を使っているが、概念は同じ。
↓ Diffie-Hellman 鍵交換シーケンス(盗聴されても安全な仕組み) ↓
sequenceDiagram participant Alice as アリス participant Eve as 盗聴者 participant Bob as ボブ Note over Alice,Bob: 公開: 黄色の絵の具を共有 Alice->>Alice: 秘密の色「赤」を選ぶ Bob->>Bob: 秘密の色「青」を選ぶ Alice->>Bob: 黄色+赤 = オレンジ を送信 Note right of Eve: オレンジは盗聴可能 Bob->>Alice: 黄色+青 = 緑 を送信 Note right of Eve: 緑も盗聴可能 Alice->>Alice: 緑 + 自分の赤 = 茶色 Bob->>Bob: オレンジ + 自分の青 = 茶色 Note over Alice,Bob: 2人とも「茶色」を共有(共通鍵成立) Note over Eve: オレンジ/緑から「茶色」を逆算できない<br/>(離散対数問題: 一方向関数)
現代の TLS は、この DH をその場で実行して、その場限りの鍵を生成する スタイルが主流。これを (EC)DHE = Elliptic Curve Diffie-Hellman Ephemeral と呼ぶ。“Ephemeral” は「儚い、使い捨て」の意味。
なぜ「使い捨ての鍵」がいいのか - 前方秘匿性
もし将来、サーバーの秘密鍵が漏れたとする。過去の通信ログを全部復号できてしまったら大事故 だ。
でも DHE のように「毎回新しい使い捨ての鍵」で暗号化していれば、サーバーの秘密鍵が漏れても、過去の通信は復号できない。これを 前方秘匿性 (Forward Secrecy) と呼ぶ。
TLS 1.3 ではこの DHE が必須になった。「過去を守る」という思想が標準化されたわけ。
第3章: ハッシュ関数と署名 - 「改ざん」と「なりすまし」を防ぐ
3-1. 暗号化 ≠ ハッシュ化(よくある誤解)
ここで超重要な区別。
- 暗号化 (Encryption): 鍵があれば元に戻せる。可逆。
- ハッシュ化 (Hashing): 元に戻せない。不可逆。
ハッシュ関数は「どんな入力からも、固定長の文字列を吐き出す関数」。同じ入力からは同じ出力。1文字変えるだけで全く違う出力。
SHA-256("hello") = 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
SHA-256("Hello") = 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969
「h」と「H」で1文字違うだけで、結果は別物。
ハッシュ関数の3つの性質(暗号学的ハッシュ関数)
- 一方向性: 出力から入力を逆算できない
- 衝突困難性: 同じ出力になる入力2つを見つけられない
- 雪崩効果: 入力が1ビット変わると出力が大きく変わる
使い所
- パスワード保存: DB にパスワードそのものを保存しない。ハッシュ値を保存する。漏れても元のパスワードに戻せない(実際は bcrypt/Argon2 などで salt とストレッチも組み合わせる)
- ファイル改ざん検出: ダウンロードしたファイルのハッシュを公式と照合
- デジタル署名の素材: 後述
3-2. 主要なハッシュアルゴリズムの世代交代
| 名前 | 時代 | 現在の評価 |
|---|---|---|
| MD5 | 1991年 | 完全に死亡。衝突が見つかった。絶対に使うな |
| SHA-1 | 1995年 | 死亡判定。Google が衝突を発見(2017年) |
| SHA-256 | 2001年〜 | 現役の主力。SHA-2 ファミリーの一員 |
| SHA-3 | 2015年 | 次世代候補。設計思想が SHA-2 と全く別 |
レガシーシステムで MD5/SHA-1 を見つけたら
古いシステムで MD5 や SHA-1 でパスワードハッシュしているのを見つけたら、それは技術的負債かつセキュリティ事故予備軍。即移行案件として上げるべき。
「LinkedIn パスワード流出事件」(2012年)では SHA-1 で 1.17億件のパスワードハッシュが流出し、ほとんどが平文に戻された。教訓: ハッシュ関数の選定は時代と共に変える必要がある。
3-3. デジタル署名 - 「これは確かに私が書きました」
暗号化が「中身を隠す」のに対して、署名は「これは本人が書いた / 改ざんされていない」を保証する仕組み。
公開鍵暗号は実は「逆方向」にも使える:
- 普通: 公開鍵で暗号化 → 秘密鍵で復号 (秘密のやり取り)
- 署名: 秘密鍵で署名 → 公開鍵で検証 (本人性の証明)
イメージで言うと、秘密鍵は 「自分しか持ってない印鑑」。公開鍵は 「その印鑑の印影一覧(市役所に登録されてるやつ)」。
署名の手順(ざっくり)
- 文書のハッシュ値を計算する
- そのハッシュ値を秘密鍵で「署名」する(暗号学的に処理する)
- 「文書 + 署名」をセットで相手に送る
検証側:
- 受け取った文書のハッシュ値を再計算
- 受け取った署名を公開鍵で展開して、中身のハッシュ値を取り出す
- 両方のハッシュ値が一致したら「改ざんされていない、本人が署名した」と確信できる
ユースケース: ソフトウェアの配布(このバイナリは確かに公式が配ったもの)、コミット署名(このコミットは確かに私のもの)、後述の TLS 証明書
↓ ハッシュとデジタル署名の流れ ↓
flowchart LR subgraph Sign["署名側(送信者)"] Doc1[文書] --> Hash1[ハッシュ関数<br/>SHA-256] Hash1 --> H1[ハッシュ値] H1 --> SignOp["秘密鍵で署名"] SK[送信者の秘密鍵] -.-> SignOp SignOp --> Sig[署名] end Doc1 --> Send[文書 + 署名を送信] Sig --> Send subgraph Verify["検証側(受信者)"] Send --> Doc2[文書] Send --> Sig2[署名] Doc2 --> Hash2[ハッシュ関数<br/>SHA-256] Hash2 --> H2[ハッシュ値A] Sig2 --> VerifyOp["公開鍵で展開"] PK[送信者の公開鍵] -.-> VerifyOp VerifyOp --> H3[ハッシュ値B] H2 --> Compare{一致?} H3 --> Compare Compare -->|Yes| OK[改ざんなし<br/>本人の署名] Compare -->|No| NG[改ざん検出] end
これで「機密性(暗号化)」「完全性(ハッシュ)」「真正性(署名)」という、セキュリティの三本柱が出揃った。
第4章: TLS の握手 - HTTPS の心臓部
4-1. SSL から TLS へ
TLS の話に入る前に名前の整理。
- SSL (Secure Sockets Layer): 1995年に Netscape が作った初代。SSL 1.0 / 2.0 / 3.0 と進化
- TLS (Transport Layer Security): 1999年に IETF(インターネット標準化団体)が標準化した次世代。SSL 3.0 をベースに改良
- 現代では すべて TLS。だが、慣習的に今でも「SSL証明書」「SSL/TLS」と呼ぶ人が多い
正しくは「TLS」だが、口語では「SSL」も生き残っている。エンジニア同士の会話では文脈で判断する。
4-2. TLS が解決する3つの問題
TLS は HTTPS の中核で、3つのことを同時にやってのける:
- 暗号化 - 通信内容を盗聴できなくする
- 完全性 - 途中で書き換えられていないことを保証
- 認証 - 通信相手が「本物のそのサーバー」であることを保証
特に3つ目が重要。暗号化だけでは「悪意あるサーバーと暗号通信」してしまう可能性があるから。これを防ぐのが 証明書 の役割(後述)。
4-3. TLS ハンドシェイクの流れ(TLS 1.3 版)
ブラウザが https://example.com にアクセスした時、内部で起きていることを順を追って見る。
[クライアント (ブラウザ)] [サーバー]
| |
| --- ClientHello -----> |
| |
| <----- ServerHello ---- |
| <----- Certificate ---- |
| <----- ServerFinished -- |
| |
| --- ClientFinished ----> |
| |
| ===== 以降、暗号化通信 ==== |
| |
ステップ1: ClientHello(クライアント挨拶) ブラウザがサーバーに「こんにちは。私はこういう暗号方式が使えます。TLS のバージョンはこれです。あと、鍵交換用にこの公開情報を送ります」と挨拶する。
ステップ2: ServerHello(サーバー挨拶) サーバーが「了解。じゃあこの暗号方式で行きましょう。私の証明書はこれです。鍵交換用の公開情報も返します」と応答。ここで証明書を送るのがミソ。
ステップ3: 証明書検証 ブラウザはサーバーの証明書を検証する(後述: 証明書チェーン)。これに失敗すると「保護されていません」というあの赤い警告が出る。
ステップ4: 鍵交換完了 Diffie-Hellman でその場限りの共通鍵を作る。お互い計算するだけで、鍵そのものは回線に流さない。
ステップ5: 暗号化開始 以降の通信は、生成した共通鍵で対称暗号 (AES など) で暗号化される。
↓ TLS 1.3 ハンドシェイクの詳細フロー ↓
sequenceDiagram participant C as クライアント(ブラウザ) participant S as サーバー Note over C,S: 1. ClientHello C->>S: 対応する暗号方式リスト<br/>TLS バージョン<br/>鍵交換用 公開情報(ECDHE) Note over C,S: 2. ServerHello + 証明書 + 鍵交換 S->>C: 選んだ暗号方式<br/>サーバー証明書<br/>鍵交換用 公開情報(ECDHE)<br/>ServerFinished Note over C: 3. 証明書チェーン検証<br/>(失敗なら警告) Note over C,S: 4. 鍵交換完了<br/>双方で共通鍵を生成 C->>S: ClientFinished Note over C,S: 5. 以降は対称暗号(AES-GCM等)で暗号化通信 C->>S: 暗号化された HTTP リクエスト S->>C: 暗号化された HTTP レスポンス
なぜ最初に公開鍵、その後対称暗号?
公開鍵暗号は 遅い。対称暗号の数百〜千倍遅い。だから大量データには向かない。
一方、対称暗号は 速い が、鍵をどう共有するかが問題(前章でやった「鍵配送問題」)。
解決策: 公開鍵暗号で「対称鍵を安全に共有する」だけやる。実データは対称暗号で高速に暗号化する。ハイブリッド方式 とも呼ばれる。これが現代の TLS の基本設計。
4-4. TLS 1.2 → 1.3 で何が変わったか
TLS 1.3 は2018年に正式リリース。1.2 から大きく変わった。
| 観点 | TLS 1.2 | TLS 1.3 |
|---|---|---|
| 握手のラウンドトリップ | 2 RTT | 1 RTT(速い) |
| 暗号方式の選択肢 | 大量にあった(多くは脆弱) | 安全なものだけ厳選 |
| 前方秘匿性 | オプション | 必須 |
| 古い暗号 | 残存 | バッサリ削除 |
| 0-RTT 再接続 | なし | あり(再接続なら即通信) |
「削るほうの設計」がポイント。TLS 1.2 までは過去のしがらみで弱い暗号方式が残っていて、それが攻撃の隙になっていた。1.3 では設計者が腹を括って削った。
↓ TLS 1.2(2 RTT) と TLS 1.3(1 RTT) の握手回数の比較 ↓
sequenceDiagram participant C12 as クライアント (TLS 1.2) participant S12 as サーバー (TLS 1.2) Note over C12,S12: TLS 1.2: 2 RTT (往復2回) C12->>S12: ClientHello S12->>C12: ServerHello + 証明書 + ServerHelloDone C12->>S12: 鍵交換 + ChangeCipherSpec + Finished S12->>C12: ChangeCipherSpec + Finished Note over C12,S12: ここから暗号化通信開始
sequenceDiagram participant C13 as クライアント (TLS 1.3) participant S13 as サーバー (TLS 1.3) Note over C13,S13: TLS 1.3: 1 RTT (往復1回) C13->>S13: ClientHello + 鍵交換 公開情報 S13->>C13: ServerHello + 証明書 + Finished<br/>(鍵交換完了) Note over C13,S13: ここから暗号化通信開始 (圧倒的に速い) C13->>S13: Finished + 暗号化された HTTP リクエスト
「選択肢を減らす」というセキュリティ設計
「自由度が高い = 安全」ではない。むしろ逆。選択肢が多いと、弱いやつを選んでしまうリスクが上がる。
これは TLS だけでなく、API 設計、認証ライブラリ、暗号ライブラリ全般に通じる原則。「危険な使い方ができる API は、いつか誰かに危険に使われる」。
Go 言語の
crypto/tlsパッケージは TLS 1.0 と 1.1 をデフォルト無効化している。「言語標準が安全な選択を強制する」良い例。
第5章: 証明書チェーン - 「本物のサーバー」をどう信じるか
5-1. なりすましの脅威
仮にあなたが https://your-bank.com にアクセスしたとする。サーバーが「私が your-bank.com です。公開鍵はこれです」と言ってきたら、信じる?
それだけだと信じられない。だって、悪意ある誰かが「私が your-bank.com です」とウソをついてくる可能性があるから。これが なりすまし攻撃。
これを防ぐには、「信頼できる第三者」がそのサーバーの身元を保証してくれる 必要がある。
その第三者を 認証局 (Certificate Authority, CA) と呼ぶ。
5-2. 証明書の正体
「SSL証明書」とは何か。簡単に言うと:
「このドメイン名の所有者は、この公開鍵を持っています」と、CAが署名したお墨付き
中身は大体こんな情報:
所有者: your-bank.com
公開鍵: (長い文字列)
有効期限: 2025-12-31
発行者: Let's Encrypt
署名: (CAの秘密鍵で署名されたデジタル署名)
ブラウザはこの証明書を受け取って:
- 発行者(CA)の公開鍵で署名を検証 → 「確かに Let’s Encrypt が発行したものだ」
- 所有者の名前を確認 → 「your-bank.com と一致している」
- 有効期限を確認 → 「まだ有効」
3つ全部 OK なら、サーバーは本物だと判断する。
5-3. でも CA は信用できるの? - ルート証明書
ここで疑問。「CA は信用できるの?」という話になる。これは 「CAの公開鍵をどうやって確実に手に入れるか」 という問題に置き換わる。
解決策はシンプルかつ大胆: OS とブラウザに最初から CA の公開鍵を埋め込んでおく。
あなたの Mac/Windows/iPhone/Android には、出荷時から数百個の CA の公開鍵(ルート証明書)が入っている。これを ルート CA ストア と呼ぶ。
ルート CA ストアの実態
- macOS: 「キーチェーンアクセス」アプリで
システムルートを見ると、Apple が信頼している CA 一覧が見られる- Firefox: 自分専用のルートストアを持っている(OS とは別管理)
- Linux サーバー:
/etc/ssl/certs/に証明書ファイル群「Apple や Microsoft や Mozilla が、出荷前に厳選してくれた CA リスト」を、私たちは黙って信用している。インターネットの信頼の根っこは、結局 OS ベンダーへの信頼にある。
5-4. ルート → 中間 → サーバー: チェーンの構造
実は CA は 階層構造 になっている。
[ルート CA]
|
| (署名)
v
[中間 CA]
|
| (署名)
v
[サーバー証明書]
- ルート CA: 最上位。秘密鍵は厳重に金庫管理。普段はオンラインで使わない
- 中間 CA: 日常業務用。ここがサーバー証明書を発行する
- サーバー証明書: あなたのサイトの証明書
なぜ中間を挟むか:
中間 CA を挟む2つの理由
- ルート CA の秘密鍵を守る: もしルート CA の秘密鍵が漏れたら、世界の信頼が崩壊する。だから普段は使わない。中間 CA が漏れても、「中間 CA を失効させる」だけで対処できる
- 失効・更新の柔軟性: 中間 CA は数年ごとに更新される。サーバー証明書は数ヶ月。ルートは数十年。階層化することで運用が回る
ブラウザが証明書を検証する時は、このチェーンを根まで辿る:
[サーバー証明書] が [中間 CA] の署名で正しい
[中間 CA] が [ルート CA] の署名で正しい
[ルート CA] は OS に埋め込まれている → 信頼OK
全部繋がって初めて「信頼チェーン完成」となる。途中が1個でも欠けたら、ブラウザは「証明書エラー」を出す。
↓ 証明書チェーンの構造と検証の流れ ↓
flowchart TD OS["OS/ブラウザの<br/>ルート CA ストア<br/>(出荷時に埋め込み)"] Root["ルート CA 証明書<br/>(自己署名)<br/>例: ISRG Root X1"] Inter["中間 CA 証明書<br/>例: Let's Encrypt R3"] Server["サーバー証明書<br/>your-bank.com"] Browser[ブラウザ検証] OS -->|信頼済み| Root Root -->|秘密鍵で署名| Inter Inter -->|秘密鍵で署名| Server Server --> Browser Browser -->|チェーン検証| Verify{すべての署名が<br/>正しいか?} Verify -->|Yes| OK["鍵マーク表示<br/>信頼OK"] Verify -->|No| NG["証明書エラー<br/>警告画面"] classDef root fill:#ffe1e1,stroke:#333,stroke-width:2px classDef inter fill:#fff4d4,stroke:#333 classDef server fill:#e1f5ff,stroke:#333 class Root,OS root class Inter inter class Server server
第6章: Let’s Encrypt が変えた世界
6-1. 2015年以前: 証明書は有料の特権だった
2015年まで、SSL 証明書は年間 1万〜10万円くらいする有料商品だった。
これは個人サイトや小さな会社には大きな壁だった。だから「ログイン画面だけ HTTPS、他は HTTP」みたいな運用が普通だった。Wi-Fi で記事を読んでいる内容は、駅員も近くの人も覗き見できた。
6-2. 2015年: Let’s Encrypt 登場
2015年、Let’s Encrypt が誕生した。電子フロンティア財団 (EFF)、Mozilla、シスコ、Akamai などが立ち上げた 無料の CA。
無料というだけでなく、完全自動化 が革命だった。
- 証明書取得: コマンド一発(
certbotというツール) - 期限: 90日(短いが、自動更新前提)
- 更新: cron で自動
これで世界が変わった。
6-3. 世界の HTTPS 化率の推移
2014年: 約 30% のサイトが HTTPS
2017年: 約 50%
2020年: 約 80%
2024年: 約 95%
10年で 30% → 95%。インフラのレベルで世界が塗り替わった。これは Let’s Encrypt の貢献が圧倒的に大きい。
Let's Encrypt の設計思想
Let’s Encrypt は「HTTPS をインフラ化する」というミッションで作られた。「証明書はビジネスではなく公共財であるべき」という思想。
ACME (Automatic Certificate Management Environment) という標準プロトコルを策定し、これが今や IETF の標準 (RFC 8555) になっている。「無料で配るだけ」でなく「業界標準を作った」のが偉大。
現在では Cloudflare の証明書、AWS Certificate Manager、Google Trust Services など、無料 + 自動化 が当たり前になった。Let’s Encrypt 以前と以後で世界が分かれる。
6-4. 短い有効期限の意味
Let’s Encrypt の証明書は 90日 で切れる。これに「短すぎ、面倒」と思う人がいるが、実は意図的に短くしている。
なぜ 90日なのか
- 失効処理を簡単に: 漏洩しても最大90日で自動的に消える
- 自動化を強制: 90日で切れるから、自動化しないと運用できない。手動運用を不可能にする
- 暗号アルゴリズムの更新を促進: 1年とかの長期証明書だと、古いアルゴリズムが長く生き残る
業界全体で「証明書を短く」が潮流。最近は Apple が「1年以上の証明書は信頼しない」とブラウザレベルで宣言した。今後 90日が標準になる可能性がある。
第7章: 中間者攻撃 (MITM) と対策
7-1. MITM とは
Man-in-the-Middle (中間者) 攻撃: 通信の途中に攻撃者が割り込んで、両者になりすます攻撃。
[あなた] --(信じている)--> [攻撃者] --(信じている)--> [本物のサーバー]
↑ ↑
実は偽サーバー 実は偽クライアント
攻撃者は両方向の通信を盗み見られる。これが TLS が防ぐべき最大の脅威。
↓ MITM 攻撃と証明書検証によるブロックの仕組み ↓
sequenceDiagram participant User as ユーザー participant MITM as 攻撃者(中間者) participant Server as 本物サーバー Note over User,Server: 攻撃シナリオ: フリーWi-Fi で割り込み User->>MITM: HTTPS 接続要求 (相手はサーバーのつもり) MITM->>Server: ユーザーになりすまし接続 Server-->>MITM: 本物の証明書 Note over MITM: 偽の証明書を作って差し替え<br/>(攻撃者の鍵で署名) MITM-->>User: 偽証明書 Note over User: 証明書検証!<br/>署名チェーンが OS のルートCAに繋がらない User->>User: 「保護されていない通信」警告 Note over User,Server: 警告を無視しない限り、攻撃は失敗 Note over User: もし警告を無視すると... User--xMITM: パスワード送信 MITM--xServer: 通信内容を盗聴/改ざん
7-2. 証明書検証が MITM を防ぐ
TLS の証明書検証が正しく行われれば、MITM はほぼ不可能。なぜなら、攻撃者は 本物のサーバーの秘密鍵を持っていない から、偽サーバーを立ててもブラウザが証明書エラーで気付く。
証明書警告を無視する罠
「このサイトは保護されていません」「証明書エラー」の警告を「えいや」で無視する人がいる。
これが MITM の入り口。フリー Wi-Fi で警告を無視してログインすると、Wi-Fi 提供者にパスワードを抜かれる可能性がある。
エンジニアとしては「自分が無視しない」だけでなく、「ユーザーが無視できないように設計する」ことも考える必要がある。これが HSTS(後述)の役割。
7-3. HSTS: 「強制 HTTPS」
HSTS (HTTP Strict Transport Security): サーバーがブラウザに「このサイトには今後絶対 HTTPS でしかアクセスするな」と宣言する仕組み。
HTTP レスポンスヘッダにこう書く:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
これを一度受け取ったブラウザは、次から http://... でアクセスしようとしても自動で https://... に切り替える。証明書エラー時の「無視して進む」ボタンも消える。
HSTS preload list
Chrome や Firefox には「最初から HTTPS 必須サイト」のリスト(HSTS Preload List)が埋め込まれている。Google、Twitter、Facebook、銀行など主要サイトはここに登録済み。
つまり、初回アクセスから HTTPS が強制される。HTTP で行こうとしても物理的に不可能。これは MITM 攻撃を根絶する強力な仕組み。
自社サービスを preload list に登録するのは可能(hstspreload.org)。ただし一度登録すると外すのが大変なので、本気の覚悟が必要。
7-4. Certificate Transparency: 「不正な証明書を検知」
歴史上、CA が誤って(あるいは強制されて)「本来発行すべきでない証明書」を発行する事件が何度かあった。
- 2011年: DigiNotar 事件 - オランダの CA が侵害され、Google など主要サイトの偽証明書が発行された。イランのユーザーが Gmail の盗聴被害に。DigiNotar は事件後数ヶ月で消滅
- 2015年: Symantec の不正発行 - 内部で「テスト用」と称して本来発行すべきでない証明書を量産。Google が激怒し、最終的に Symantec 系証明書は全ブラウザで信頼を失った
これらを受けて生まれたのが Certificate Transparency (CT)。
CT の仕組み
すべての CA は、発行した証明書を 公開ログ に登録する義務がある。誰でもそのログを監視できる。
もし誰かが
your-bank.comの偽証明書を発行したら、ログに記録される →your-bank.comの運営者は自分のドメインで知らない証明書が発行されたことを検知できる → 緊急対応に入るこれは「不正発行を防ぐ」のではなく「不正発行されたら必ずバレる」という設計。完璧な防御がない世界での現実解。
Chrome は CT ログに登録されていない証明書を拒否する(2018年以降)。これにより業界全体が CT 必須に変わった。
第8章: 量子コンピュータと暗号の未来
8-1. 量子コンピュータ脅威論
量子コンピュータが現実のものになると、RSA も ECC も Diffie-Hellman も、全部破られる と言われている。
なぜか。Shor のアルゴリズム という量子計算用の手法を使うと、「素因数分解」と「離散対数」が現実的な時間で解けてしまうから。
通常の PC: 2048bit RSA を破るのに数十億年
十分強力な量子PC: 数時間〜数日
これは理論上は1994年から分かっていたが、現実の量子コンピュータがその規模に到達するのは時間の問題。NIST(米国標準技術研究所)は「2030年頃には危険」と見ている。
8-2. PQC: ポスト量子暗号
これに備えて、Post-Quantum Cryptography (PQC) が研究されている。量子コンピュータでも破れない新世代の暗号方式。
NIST は2016年から世界中の研究者を集めて PQC の標準化コンペを開催。2024年に最初の標準 (FIPS 203, 204, 205) が制定された。
| 名称 | 用途 | 基盤数学 |
|---|---|---|
| ML-KEM (Kyber) | 鍵交換 | 格子問題 |
| ML-DSA (Dilithium) | 署名 | 格子問題 |
| SLH-DSA (SPHINCS+) | 署名 | ハッシュベース |
「ハーベスト・ナウ、デクリプト・レイター」の脅威
「今は暗号通信を盗んでおいて、将来量子コンピュータができてから解読する」という攻撃シナリオがある。
機密性が長期間必要なデータ(国家機密、医療情報、企業秘密)は、今からポスト量子暗号への移行を考える必要がある。Google、Cloudflare、Apple は既に PQC をハイブリッドで実装し始めている。
エンジニアとしては「自分の作っているサービスのデータは10年後も秘密である必要があるか?」を考える視点を持つべき。
8-3. ハイブリッド方式
完全に PQC に切り替えるのではなく、既存の暗号 + PQC を併用 するハイブリッド方式が現在の主流。
共通鍵 = HKDF( ECDHE鍵 || Kyber鍵 )
ECDHE と Kyber、両方の出力を混ぜて使う。どちらか片方でも安全なら全体が安全。これは「PQC が本当に安全かまだ確証がない」という慎重論への配慮。
既に動いている PQC
- Chrome / Edge: 2024年から Google サービス相手に Kyber ハイブリッドを使用
- Cloudflare: 一部のエンタープライズ顧客向けに PQC 提供
- AWS: 一部 API で実装
知らないうちに、あなたのブラウザは既にポスト量子暗号を喋っている可能性がある。
第9章: TLS は「どこで終端」するのか - 現代インフラの真実
9-1. TLS 終端の場所
「サーバー」が TLS を喋っていると思いがちだが、現代の Web インフラでは TLS を喋っているのはアプリサーバーではないことが多い。
[ユーザー] --(HTTPS)--> [CDN / LB] --(HTTP)--> [アプリサーバー]
↑
ここで TLS 終端
CDN (Content Delivery Network) や Load Balancer (L7 LB) で TLS を 終端 し、内部ネットワークでは HTTP で通信する、という構成が一般的。
9-2. なぜそうするのか
TLS 終端を前段でやる理由
- 証明書の一元管理: 何百台のアプリサーバーに証明書を配るのは大変。前段の数台だけに証明書を入れれば済む
- CPU 負荷の分散: TLS 処理は CPU を食う。専用の前段に任せれば、アプリサーバーは本業に集中できる
- WAF や DDoS 防御: 前段で HTTPS を解いて、中身を検査してから後段に流す。中身が暗号化されたままだと WAF が効かない
- TLS バージョン管理の集約: 古い TLS バージョンの廃止などを前段だけで対応できる
9-3. 主要な TLS 終端のレイヤー
| レイヤー | 例 | 特徴 |
|---|---|---|
| CDN | Cloudflare, Akamai, Fastly | 世界中のエッジで終端。最速 |
| L7 LB | AWS ALB, GCP HTTPS LB | クラウドネイティブ |
| Reverse Proxy | nginx, HAProxy, Envoy | オンプレ・自前運用 |
| Service Mesh | Istio, Linkerd | サービス間通信を暗号化(mTLS) |
内部通信を平文にする罠
「前段で TLS 終端したから、内部は HTTP でいいや」というのは 古い設計。
内部ネットワークも信頼できる時代は終わった。クラウド時代では、データセンター内でも盗聴・改ざんのリスクがある(ゼロトラスト の考え方)。
現代的には mTLS (mutual TLS) で内部通信も全部暗号化&相互認証する。Service Mesh の主な役割の一つ。
第10章: AES vs ChaCha20 - 「具」の使い分け
TLS の中で実際にデータを暗号化するアルゴリズムにも種類がある。現代の主役は2つ:
10-1. AES-GCM
AES = Advanced Encryption Standard。GCM = Galois/Counter Mode。
- 1998年に米国で公募された標準暗号、ベルギーの研究者2人が設計
- 現代の CPU には AES-NI という専用命令が入っている → ハードウェアで爆速
- デスクトップ・サーバーでは圧倒的にこれが速い
10-2. ChaCha20-Poly1305
ChaCha20 = ストリーム暗号、Poly1305 = 認証
- 2008年、暗号研究者 Daniel J. Bernstein が設計
- 専用ハードウェアなしのソフトウェア実装で速い
- モバイル端末や IoT で AES より速いことが多い
なぜ2つあるのか
AES は CPU の専用命令があれば爆速だが、それがない環境(古いスマホ、組み込み機器)では遅い。
ChaCha20 は専用命令なしのソフト実装で速く設計されている。だからモバイルや IoT に向く。
TLS 1.3 は「クライアントの環境に応じて速い方を選ぶ」設計。サーバーは両方サポートしておき、ブラウザが自分に最適な方をリクエストする。
Cloudflare がこの仕組みを大規模に展開して、モバイルユーザーの体感速度が劇的に上がった事例がある。エンジニアの選択が世界の体感を変える例。
第11章: 廃止された TLS - 過去の教訓
11-1. TLS 1.0 / 1.1 はもう使うな
TLS 1.0 (1999年) と TLS 1.1 (2006年) は、2020年に主要ブラウザでデフォルト無効化された。
なぜ廃止されたか
過去に発見された脆弱性が修正できないか、根本的に設計が古いから。
- BEAST 攻撃 (2011年): TLS 1.0 の CBC モード実装の欠陥を突く
- POODLE 攻撃 (2014年): SSL 3.0 の脆弱性を悪用して TLS 通信を降格させる
- CRIME / BREACH (2012年): 圧縮機能を使って情報漏洩
- Heartbleed (2014年): OpenSSL のバグでサーバーメモリの内容を取り放題
Heartbleed は厳密には TLS バージョン自体の欠陥ではなく実装バグだが、当時の TLS インフラに大打撃を与えた。「OpenSSL という1つのライブラリのバグが、世界中の HTTPS サーバーの過半数を脆弱にした」という事件。
11-2. 何が学べるか
これらの過去事例から、エンジニアが学ぶべきこと:
- 「破られていない」のは「まだ破られていない」の意味: 暗号は時代と共に弱くなる
- 依存ライブラリの単一障害点: OpenSSL、libssl、各言語の標準ライブラリのバグは全インターネットに波及する
- 「動いてるから触らない」が一番危ない: 暗号系のライブラリこそ常に最新を保つ
- 設定の Best Practice を追え: Mozilla の SSL Configuration Generator など、業界推奨の設定を毎年確認
エンジニア向けの「TLS 健康診断」ツール
- SSL Labs SSL Server Test (ssllabs.com): URL を入れるだけで、TLS 設定を A〜F でスコアリングしてくれる。プロダクションサイトで定期的にチェック推奨
- Mozilla SSL Configuration Generator (ssl-config.mozilla.org): nginx, Apache, Envoy などの安全な TLS 設定を自動生成
- testssl.sh: OSS のコマンドラインツール。CI に組み込んで継続監視も可能
まとめ: あなたが今後 HTTPS を見る時に思い出してほしいこと
この記事のエッセンス
暗号は2000年以上の歴史がある - シーザー暗号からポスト量子暗号まで、人類はずっと「秘密を守る」戦いを続けてきた
公開鍵暗号は1976年の革命 - 「同じ鍵を共有しなくても秘密を守れる」というアイデアが世界を変えた
TLS はハイブリッド設計 - 公開鍵で対称鍵を共有 → 対称鍵で本データを暗号化、という二段構え
証明書チェーンは「信頼の連鎖」 - OS に埋め込まれたルート CA を根として、すべての信頼が成り立っている
Let’s Encrypt が世界を変えた - 2015年以降、無料 + 自動化により HTTPS が全インターネットの前提になった
TLS 1.3 は「削る設計」 - 安全のためには選択肢を狭めるべき、という価値観
量子コンピュータ時代に備えるべき - PQC への移行は既に始まっている
TLS は CDN / LB で終端されることが多い - 「サーバーが TLS 喋ってる」とは限らない
過去の脆弱性から学べ - POODLE, BEAST, Heartbleed, それぞれが教訓を残している
あなたが明日から少し違う目で見られること
- URL の鍵マークをクリックすると、証明書の発行者 (Let’s Encrypt? DigiCert?) が見られる。誰があなたの信頼を支えているか分かる
- ブラウザの「保護されていない通信」警告は、軽い気持ちで無視しちゃダメ
- 「無料の Wi-Fi で銀行アクセスは大丈夫?」と聞かれたら、「HTTPS で HSTS が効いてれば理屈上は大丈夫、でも証明書警告だけは絶対無視するな」と答えられる
- 「カード番号入力フォーム、HTTP だったら絶対入れるな」と即座に分かる
考えてみよう
- もし全インターネットの CA が一斉に侵害されたら、人類はどうやって信頼を再構築できる?
- 量子コンピュータができてから慌てて暗号を切り替えるのと、今から徐々に移行するのと、どちらが正しい?
- あなたが将来サービスを設計する時、「証明書」「mTLS」「ゼロトラスト」をどこに組み込む?
- Heartbleed や DigiNotar など過去の TLS 事件を踏まえると、「OpenSSL 1ライブラリへの依存」をあなたはどう扱う?
さらに深掘りするなら
- 書籍: 『暗号技術入門 第3版 秘密の国のアリス』(結城浩) - 日本語で読める最高の入門書。図解豊富で「なぜそうなるか」が腹落ちする
- 書籍: 『暗号解読』(サイモン・シン) - シーザー暗号からエニグマ、現代暗号まで歴史小説のように読める名著
- 書籍: 『Bulletproof TLS and PKI』(Ivan Ristic) - TLS の本気の解説書。プロ向け
- ドキュメント: Mozilla Server Side TLS - 業界推奨の TLS 設定ガイド
- 動画: Computerphile の暗号関連動画 (YouTube) - 短く分かりやすい英語解説
- 記事: Cloudflare Blog の暗号系記事 - 業界最前線の実装事例
- OSS: OpenSSL, BoringSSL, LibreSSL のソースコード - 現代 TLS のリファレンス実装
カリキュラム本編で関連する章
- セキュリティ章 - TLS 設定、証明書取得、HSTS 設定の実装
- インフラ章 - nginx での TLS 終端、Let’s Encrypt 自動化、CDN 設定
- Go 章 -
crypto/tlsパッケージで TLS サーバー / クライアントを書く
次の読み物
05_OSの基礎.md をまだ読んでいなければ次に。OS の基礎概念(プロセス、メモリ、ファイルシステム)の話。
「アプリを動かす土台」を理解すると、TLS のような上位の仕組みも「なぜそう動くか」が見えてくる。次もスマホで気楽にどうぞ。