SSL/TLS とは — HTTPS 暗号化の仕組みと証明書 のサムネイル

SSL/TLS とは — HTTPS 暗号化の仕組みと証明書

⏱ 約 18 分 view 64 like 0 LOG_DATE:2026-05-09
目次 / TOC

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) #

TLS 1.3 ハンドシェイク (1-RTT) クライアントが最初に暗号スイートと鍵共有を一気に提示 → 1 往復で鍵確立完了 Client Server 1 ClientHello supported_versions, cipher_suites, key_share (ECDHE 公開鍵), signature_algorithms, SNI 2 ServerHello + {EncryptedExtensions, Certificate, CertificateVerify, Finished} ServerHello で鍵共有完了 → ServerHello 直後から暗号化開始 ({...} は暗号化済み) この時点で双方が以下を保有 handshake_traffic_secret application_traffic_secret_0 3 {Finished} (Client → Server) ハンドシェイク完了の MAC を返答 → 以降 application_data は対称暗号化のみ ★ TLS 1.2 との違い (赤字部分が削除/統合) • TLS 1.2 では ClientHello → ServerHello → Certificate → ServerKeyExchange →   ServerHelloDone → ... と 2 往復 (2-RTT) 必要だった • TLS 1.3 では key_share を ClientHello に乗せ、ServerHello 1 通で鍵確立 → 1-RTT • ServerHello 直後から暗号化されるため、証明書も暗号化済み (TLS 1.2 は平文) • 古い暗号 (RSA 鍵交換, CBC, 3DES, RC4, MD5, SHA-1) は 完全削除 • 鍵交換は ECDHE / DHE のみ = Forward Secrecy が 必須 ★ 0-RTT (Early Data) と再開 • 過去に同じサーバとセッションを確立済みなら、PSK (Pre-Shared Key) を使って   0-RTT で application_data を投げられる • 0-RTT データは replay 可能性があるため、副作用のない idempotent な GET 等に限定すべき • PSK + (EC)DHE モードを使えば、再開時も Forward Secrecy を維持できる

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_SHA256
  • TLS_AES_256_GCM_SHA384
  • TLS_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 の証明書)

クライアントは:

  1. サーバから受け取ったチェーンを順に検証
  2. 各証明書の有効期間・署名・拡張をチェック
  3. 最終的にチェーンが 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・セキュリティ担当者全員にとって意味がある。