SSL/TLS (Transport Layer Security) #
Transport Layer Security (TLS) と、その前身の Secure Sockets Layer (SSL) は、ネットワーク上の通信に「機密性 (盗聴防止)」「完全性 (改ざん検出)」「認証 (なりすまし防止)」を提供する暗号通信プロトコルである。HTTPS の "S" は SSL/TLS のことであり、Web、メール (SMTPS / IMAPS)、VPN、API、IoT、ゲーム、独自プロトコル — インターネット上のほぼ全ての安全通信が SSL/TLS の上に乗っている。
歴史的経緯から「SSL」と「TLS」が混在して呼ばれるが、現代運用されているのは TLS のみ (SSL は 2011 年に IETF が deprecated 宣言)。それでも「SSL 証明書」「SSL 化」といった慣用表現は今も残る。本稿でも文脈に応じて「SSL/TLS」と「TLS」を使い分ける。
1. SSL/TLS の歴史 #
1.1 SSL 1.0 (1994, Netscape, 未公開) #
1994 年、Netscape が Web ブラウザでクレジットカード番号などを安全に送るため SSL 1.0 を社内設計。設計欠陥が多すぎて世に出ることなく破棄された。
1.2 SSL 2.0 (1995) #
1995 年、Netscape が SSL 2.0 を公開。Netscape Navigator 1.1 以降に組み込まれ、世界中の Web に広まった最初のバージョン。しかし MAC と暗号化に同じ鍵を使う、ハンドシェイクの完全性を後で検証しないなど、根本的な欠陥が残されていた。
1.3 SSL 3.0 (1996) #
1996 年、SSL 2.0 の脆弱性を踏まえ全面リファクタリングして SSL 3.0 を公開。レコード層とハンドシェイク層を分離する現代 TLS の基本構造はここで確立した。後の RFC 6101 (2011 年) で参考情報として文書化。2014 年の POODLE 攻撃で完全に死亡 (RFC 7568 で禁止)。
1.4 TLS 1.0 (1999, RFC 2246) #
1999 年、IETF が SSL 3.0 をベースに TLS 1.0 として標準化 (RFC 2246)。Netscape の独占から IETF オープン標準へ移行した節目。SSL 3.0 とは互換性がなく、ハンドシェイク中の Premaster Secret 計算など細部で改良。
1.5 TLS 1.1 (2006, RFC 4346) #
CBC モードの IV を予測可能にしてしまう実装上の問題を修正。Explicit IV を導入し、後の BEAST 攻撃 (2011) を予防。実用上は TLS 1.0 → 1.2 への中継ぎでしかなかった。
1.6 TLS 1.2 (2008, RFC 5246) #
TLS の長い黄金時代の始まり。SHA-1 固定だった PRF/MAC を任意のハッシュに切替可能にし、AEAD 暗号 (GCM, ChaCha20-Poly1305) のサポート、署名アルゴリズムの拡張など、現代暗号への入り口を作った。今でも実運用の主流で、TLS 1.3 と並走している。
1.7 TLS 1.3 (2018, RFC 8446) #
10 年ぶりの大改訂。後方互換性を犠牲にしてプロトコルを根本から作り直した:
- ハンドシェイクが 1 往復 (1-RTT) に短縮、再接続なら 0-RTT
- 古くて脆弱な暗号 (RSA 鍵交換、CBC モード、3DES、RC4、MD5、SHA-1) を全て削除
- AEAD 暗号 (AES-GCM / ChaCha20-Poly1305 / AES-CCM) を強制
- Forward Secrecy を必須化 (DHE / ECDHE のみ)
- ServerHello 直後からの暗号化でメタデータ漏洩を最小化
ChromeおよびFirefoxは2018年から本格対応。現代の HTTPS は 95% 以上が TLS 1.2 か 1.3 で動いている (TLS 1.0/1.1 は 2020 年に主要ブラウザがサポート終了)。
1.8 TLS 1.3 以降 (Encrypted Client Hello など) #
TLS 1.3 自体は枯れているが、その上で ECH (Encrypted Client Hello) で SNI (接続先ホスト名) を暗号化する拡張が draft 段階で進行中。検閲回避とプライバシー強化が目的。
2. SSL/TLS の役割と OSI 上の位置 #
+----------------------+
| Application 層 | HTTP / SMTP / IMAP / FTP ...
+----------------------+
| ★ TLS | (本記事) — 暗号化・認証・改ざん検出
+----------------------+
| Transport 層 | TCP (TLS) / UDP+QUIC (TLS 1.3 内蔵)
+----------------------+
| Network 層 | IP
+----------------------+
| Data Link / Physical | Ethernet / Wi-Fi / 光ファイバ
+----------------------+
TLS は 「Transport の上、Application の下」 に挟まる薄い層で、アプリケーションプロトコル (HTTP, SMTP, ...) からは「ただの暗号化されたバイトストリーム」として透過的に見える。これが TLS の最大の設計美で、HTTP を一切改造せずに HTTPS にできた理由である。
TLS が提供するのは次の 3 つ:
- 機密性 (Confidentiality): 通信内容を盗聴されても読めない (対称暗号 = AES-GCM など)
- 完全性 (Integrity): 通信内容が改ざんされたら検出できる (AEAD の認証タグ)
- 認証 (Authentication): 通信相手が「本物」であることを保証する (X.509 証明書 + PKI)
特に 認証なしの暗号化は無意味 (中間者が攻撃者に置き換わっていれば、攻撃者と暗号化通信して終わり) であることに注意。SSL/TLS が「証明書とのセット」で初めて意味を持つのはこのため。
3. TLS のハンドシェイク #
ハンドシェイクは TLS の心臓部。鍵交換と相手認証を完了させ、以降の通信に使うセッション鍵を確立する。TLS 1.2 と TLS 1.3 で大きく変わるので両方説明する。
3.1 TLS 1.3 ハンドシェイク (1-RTT) #
3.2 TLS 1.2 ハンドシェイクとの比較 #
TLS 1.2 のフルハンドシェイクは 2-RTT で次のように進む。
Client Server
| ClientHello |
| (supported cipher suites, random) |
|-------------------------------------->|
| |
| ServerHello |
| (chosen cipher, random) |
| Certificate (X.509 chain) |
| ServerKeyExchange (ECDHE 公開鍵) |
| ServerHelloDone |
|<--------------------------------------|
| |
| ClientKeyExchange (ECDHE 公開鍵) |
| ChangeCipherSpec |
| Finished |
|-------------------------------------->|
| |
| ChangeCipherSpec |
| Finished |
|<--------------------------------------|
| |
|======== Application Data (暗号化) ====|
ServerHello から ChangeCipherSpec までが平文で流れるため、TLS 1.2 では「どの証明書を使ったか」「どのバージョン/暗号スイートを選んだか」がネットワーク上で観察可能だった。TLS 1.3 はこれを暗号化することでメタデータ漏洩を抑えた。
3.3 暗号スイート (Cipher Suite) #
TLS 1.2 までの暗号スイートは「鍵交換 + 認証 + 対称暗号 + MAC」の 4 要素を 1 つの文字列で指定する複雑な仕組みだった。
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
│ │ │ │
│ │ │ └─ HKDF/PRF のハッシュ
│ │ └─ 対称暗号 (AEAD)
│ └─ 認証 (サーバ証明書の鍵タイプ)
└─ 鍵交換 (Forward Secrecy あり)
TLS 1.3 では「鍵交換と認証は別で交渉」されるようになり、暗号スイートは対称暗号 + ハッシュだけを指定する。代表的な TLS 1.3 暗号スイート:
TLS_AES_128_GCM_SHA256TLS_AES_256_GCM_SHA384TLS_CHACHA20_POLY1305_SHA256
4. 証明書と PKI #
4.1 X.509 証明書 #
TLS の認証は X.509 証明書 に依存する。証明書は次の情報を含む構造化データ (DER でバイナリ符号化、PEM で base64 + ヘッダ表記)。
- Subject (発行先) —
CN=hackinglabo.com、SAN (Subject Alternative Name) で複数ドメイン - Issuer (発行者) — どの CA が署名したか
- Validity — 有効期間 (現在は最大 398 日)
- Public Key — このドメインの公開鍵 (RSA / ECDSA / Ed25519)
- Extensions — Key Usage, Extended Key Usage, AIA, CRL DP, SCT (Certificate Transparency)
- Signature — 上記全フィールドへの CA の署名
4.2 証明書チェーンと信頼の連鎖 #
実際のサーバ証明書は、CA の署名で「親 → 子」とつながる証明書チェーンの末端にある。
[Root CA] (OS / ブラウザにバンドル、自己署名)
│ 署名
↓
[Intermediate CA] (実運用で使われる中間 CA)
│ 署名
↓
[Server Certificate] (hackinglabo.com の証明書)
クライアントは:
- サーバから受け取ったチェーンを順に検証
- 各証明書の有効期間・署名・拡張をチェック
- 最終的にチェーンが OS/ブラウザのトラストストアに登録された Root CA に行き着けば信頼成立
Let's Encrypt のルート CA ISRG Root X1 は 2016 年から主要 OS にバンドルされている。
4.3 失効確認 (CRL / OCSP / OCSP Stapling) #
証明書は有効期限内でも、秘密鍵漏洩などで失効する場合がある。失効確認の方法:
| 方式 | 仕組み | 問題点 |
|---|---|---|
| CRL (Certificate Revocation List) | CA が「失効リスト」を公開、クライアントが定期取得 | ファイルが巨大化 |
| OCSP (Online Certificate Status Protocol) | 証明書ごとに CA に問い合わせ | プライバシー漏洩 + 遅延 |
| OCSP Stapling | サーバが事前に OCSP 応答を取得し、ハンドシェイクに同梱 | 現代の主流 |
| CRLite / OneCRL | ブラウザがブルームフィルタで一括配布 | Chrome / Firefox で採用 |
4.4 Certificate Transparency (CT) #
不正発行を検出するため、CA は発行した全証明書を公開ログに記録することが求められる (Chrome は 2018 年から CT 必須化)。証明書には少なくとも 2 つの独立 CT ログから取得した SCT (Signed Certificate Timestamp) が埋め込まれる。
これにより、攻撃者や悪意ある CA が「特定ドメイン宛の偽証明書」を密かに発行することが事実上不可能になった。研究者・運用者は crt.sh で自ドメイン向けに発行された全証明書を監視できる。
4.5 Let's Encrypt と ACME #
2015 年に開始した Let's Encrypt は無料・自動化で証明書を発行する CA で、現在世界の HTTPS の半分以上を占める。プロトコルは ACME (Automatic Certificate Management Environment, RFC 8555) で、certbot などのクライアントがドメイン所有確認 (DNS-01 / HTTP-01 / TLS-ALPN-01) を経て 90 日有効な証明書を自動取得・更新する。
5. 暗号アルゴリズム #
5.1 鍵交換 (Key Exchange) #
セッション鍵を「安全に共有する」ための仕組み。
| アルゴリズム | 解説 | 状況 |
|---|---|---|
| RSA Key Exchange | クライアントが Premaster Secret を RSA で暗号化送信 | TLS 1.3 で削除 (Forward Secrecy なし) |
| DHE (Diffie-Hellman Ephemeral) | 一時的な DH 鍵で共有 | 安全だが遅い |
| ECDHE (Elliptic Curve DHE) | 楕円曲線版 DHE | TLS 1.3 の主流 (X25519, P-256) |
Forward Secrecy (FS, PFS): 長期の秘密鍵が将来漏洩しても、過去の通信は復号できない性質。DHE / ECDHE のみが提供する。RSA 鍵交換ではこれが得られない (将来 RSA 秘密鍵が漏れたら過去の全通信が復号可能) ため TLS 1.3 で禁止された。
5.2 対称暗号 (Bulk Cipher) #
ハンドシェイク後の本番通信で使う。
| 暗号 | モード | 用途 | 推奨度 |
|---|---|---|---|
| AES-128-GCM / AES-256-GCM | AEAD | 万能 | ◎ (TLS 1.3 必須) |
| ChaCha20-Poly1305 | AEAD | モバイル (AES NI なし) で高速 | ◎ |
| AES-CCM | AEAD | IoT 向け | ○ |
| AES-CBC + HMAC | 非 AEAD | TLS 1.2 まで | △ (BEAST/Lucky13 攻撃) |
| 3DES / RC4 / NULL | レガシー | — | ✗ (削除) |
AEAD (Authenticated Encryption with Associated Data) は暗号化と完全性検証を 1 つの操作で行う方式で、padding oracle 攻撃 (Lucky13, BEAST) を構造的に防ぐ。TLS 1.3 は AEAD のみを許容する。
5.3 署名 (Signature) と認証 #
サーバ証明書の署名鍵で「サーバ本物」を証明する。
| 鍵 | 状況 |
|---|---|
| RSA-2048 / RSA-3072 | 古典的、まだ広く使われる |
| ECDSA P-256 / P-384 | 楕円曲線、鍵が短くハンドシェイクが速い |
| Ed25519 | TLS 1.3 で標準化、最新 |
6. SSL/TLS 主要コマンド #
6.1 openssl s_client — TLS クライアント診断 #
# 接続して証明書チェーンとハンドシェイクを観察
openssl s_client -connect hackinglabo.com:443 -servername hackinglabo.com
# TLS バージョン指定
openssl s_client -connect example.com:443 -tls1_3
openssl s_client -connect example.com:443 -tls1_2
# 証明書のみ取得
openssl s_client -connect example.com:443 -showcerts < /dev/null
# 暗号スイート列挙
openssl s_client -connect example.com:443 -cipher 'ECDHE-RSA-AES256-GCM-SHA384'
6.2 openssl x509 — 証明書の中身を見る #
# サーバから取って直接表示
echo | openssl s_client -connect example.com:443 2>/dev/null \
| openssl x509 -noout -text
# 証明書ファイルから
openssl x509 -in cert.pem -noout -subject -issuer -dates -ext subjectAltName
# フィンガープリント
openssl x509 -in cert.pem -noout -fingerprint -sha256
6.3 openssl で自己署名証明書を作る #
# 鍵生成 (ECDSA P-256)
openssl ecparam -genkey -name prime256v1 -out key.pem
# CSR 作成
openssl req -new -key key.pem -out csr.pem \
-subj "/CN=test.example.com"
# 自己署名証明書 (1 年有効)
openssl req -x509 -key key.pem -out cert.pem -days 365 \
-subj "/CN=test.example.com"
6.4 curl で TLS デバッグ #
# 詳細 TLS ハンドシェイクログ
curl -v --tls-max 1.3 https://example.com
# 証明書検証を一時無効 (テスト用、本番では絶対 NG)
curl -k https://self-signed.example.com
# TLS バージョン強制
curl --tlsv1.2 --tls-max 1.2 https://example.com
6.5 nmap で TLS 設定をスキャン #
# ssl-enum-ciphers — サポート暗号スイート、TLS バージョン、評価
nmap --script ssl-enum-ciphers -p 443 hackinglabo.com
# 証明書情報
nmap --script ssl-cert -p 443 hackinglabo.com
# Heartbleed チェック
nmap --script ssl-heartbleed -p 443 example.com
6.6 testssl.sh — 包括的な TLS 監査 #
# 全項目スキャン
./testssl.sh https://hackinglabo.com
# 脆弱性のみ
./testssl.sh -U https://hackinglabo.com
設定ミス (古いプロトコル有効、弱い暗号、CT 未対応など) を一発で洗い出せる定番。Qualys SSL Labs (ssllabs.com/ssltest) のオンライン版もある。
7. セキュリティ — 著名な攻撃と対策 #
7.1 BEAST (2011) — TLS 1.0 / CBC #
CBC モードの予測可能な IV を悪用し、平文を 1 byte ずつ復元する。対策: TLS 1.1+ の Explicit IV、または RC4 (後に RC4 自体が破られたので不採用)、最終的には CBC を捨てて AEAD へ移行。
7.2 CRIME / BREACH (2012) — 圧縮 #
TLS / HTTP の圧縮を悪用して、Cookie などの機密文字列を 1 byte ずつリーク。対策: TLS 圧縮 (RFC 3749) を完全無効化、HTTP 側でも機密データを応答に乗せない。
7.3 Lucky 13 (2013) — CBC + HMAC のタイミング差 #
CBC モードと HMAC を組み合わせる際の処理時間差から padding を推測。対策: AEAD への移行 (現代は無関係)。
7.4 Heartbleed (2014) — OpenSSL バグ #
OpenSSL の Heartbeat 拡張のバウンドチェック忘れで、サーバメモリを最大 64KB 任意リーク。秘密鍵まで漏洩可能で過去最悪級の脆弱性。CVE-2014-0160。対策: OpenSSL の即時パッチ + 全サーバの鍵入れ替えと証明書再発行。Yahoo!、Google、AWS など世界中が同時に対応した。
7.5 POODLE (2014) — SSL 3.0 #
SSL 3.0 の CBC パディング検証の甘さで平文を復元できる。対策: SSL 3.0 を完全に無効化 (RFC 7568)、TLS_FALLBACK_SCSV でダウングレード防止。
7.6 FREAK / Logjam (2015) — Export-Grade 暗号 #
90 年代の米国輸出規制で残された 512 bit RSA / 512 bit DH を再活性化させてダウングレードさせる。対策: 全 EXPORT 暗号を削除、DH パラメータを 2048 bit 以上に。
7.7 DROWN (2016) — SSL 2.0 鍵共有 #
同じ秘密鍵を SSL 2.0 と TLS で共用していると、SSL 2.0 経由で TLS の通信を復号できる。対策: SSL 2.0 を世界中のサーバから完全排除。
7.8 ROBOT (2017) — RSA Bleichenbacher #
19 年前の Bleichenbacher 攻撃 (1998) のバリエーションが、Facebook / PayPal / Cisco / IBM など多数の TLS 実装で再発見された。対策: RSA 鍵交換の代わりに ECDHE。TLS 1.3 で RSA 鍵交換は完全削除。
7.9 中間者攻撃 (MITM) と 証明書検証バイパス #
不正な CA の発行 (DigiNotar 2011, Symantec 2017) や、企業/家庭ルータの「TLS インスペクション」での証明書差し替えなど。対策:
- HSTS (HTTP Strict Transport Security) — 一度 HTTPS で接続したサイトは平文 HTTP を拒否
- HPKP (廃止済み) → CT + ブラウザ側 CRLite + Public Key Pinning は限定的に利用
- DANE / TLSA — DNSSEC で証明書を縛る (運用ハードル高)
- Certificate Transparency — 不正発行を可視化
8. 運用設定の現実解 #
§5〜§7 で扱った暗号アルゴリズム選択や脆弱性史を踏まえると、実運用で押さえるべきポイントは「プロファイル選び」と「勝手に古びさせない仕組み」の 2 つに集約される。
8.1 サーバ設定は Mozilla のテンプレート 1 つで足りる #
ハンドシェイクと暗号スイートの組み合わせを自前で考える必要はない。Mozilla SSL Configuration Generator (ssl-config.mozilla.org) が 3 プロファイルをそのままコピペで提供してくれており、これが事実上の業界標準になっている。
| プロファイル | 対応 TLS | 想定読者 |
|---|---|---|
| Modern | 1.3 のみ | API / 社内系で「最新ブラウザだけ」で良いとき |
| Intermediate | 1.2 + 1.3 | 一般的な Web サイト (これを選んでおけば外さない) |
| Old | 1.0 〜 1.3 | Windows XP / Android 4 への互換が法的に必要な場合のみ |
8.2 「気付いたら古い」を起こさないための仕組み #
設定そのものよりも、「設定が古びても気付ける」「古びたら自動で更新される」運用ループを組むほうが本質的:
- 証明書を
certbot/acme.sh+ cron で自動更新。手動更新を運用に残すと期限切れ事故は必ずいつか起こる testssl.shか Qualys SSL Labs を定期実行 (年 2 回 + 重大 CVE 公表時)。新しい脆弱性が出ても、既存設定が露出していることに自分で気付ける- CT ログを監視: crt.sh で自ドメインに不正発行された証明書の早期発見
- HTTP → HTTPS 301 リダイレクト + HSTS preload 登録 (hstspreload.org) で、平文 HTTP を構造的に閉じる
- OCSP Stapling 有効化: 失効確認の遅延・プライバシー漏洩を解消
ECH (Encrypted Client Hello) や量子耐性暗号への移行は 2026 年時点でまだ draft / 試験段階。情報を追っておく程度で、本番投入は急がなくてよい。
SSL/TLS は「勝手に動いている安心の層」と思われがちだが、その実態は過去 30 年の暗号研究と多くの脆弱性発見を経て今に至る、極めて入念な層である。証明書の自動更新を 1 度怠れば全ユーザがエラー画面に当たり、ハンドシェイクの設定を 1 つ間違えれば帯域・レイテンシ・互換性が一気に劣化する。現代インターネットの信頼の根幹として、原理を一度押さえておくことは、Web 開発者・SRE・セキュリティ担当者全員にとって意味がある。