メインコンテンツまでスキップ

TLS/SSL - 通信の暗号化

このドキュメントの目的

TLS(Transport Layer Security) の仕組みを理解し、安全な通信を実現するための知識を身につけます。


TLS/SSLとは

TLS(Transport Layer Security):

  • インターネット上の通信を暗号化するプロトコル
  • HTTPS、メール(SMTPS/IMAPS)、VPNなどで使用
  • SSLの後継(SSL 3.0 → TLS 1.0 → TLS 1.2 → TLS 1.3)
TLSが提供するセキュリティ:

┌─────────────────────────────────────────────────────────────┐
│ TLSの3つの保証 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 機密性(Confidentiality) │
│ → 通信内容を第三者に読まれない │
│ → 共通鍵暗号(AES等)で実現 │
│ │
│ 2. 完全性(Integrity) │
│ → 通信内容が改ざんされていないことを保証 │
│ → MAC(メッセージ認証コード)で実現 │
│ │
│ 3. 認証(Authentication) │
│ → 通信相手が本物であることを確認 │
│ → 証明書とデジタル署名で実現 │
│ │
└─────────────────────────────────────────────────────────────┘

TLSの位置づけ

OSI参照モデルとTLSの位置:

┌─────────────────────────────────────┐
│ アプリケーション層 │ HTTP, SMTP, FTP など
├─────────────────────────────────────┤
│ ★ TLS層 │ ← ここで暗号化
├─────────────────────────────────────┤
│ トランスポート層 │ TCP
├─────────────────────────────────────┤
│ ネットワーク層 │ IP
├─────────────────────────────────────┤
│ データリンク層 │ Ethernet
└─────────────────────────────────────┘

TLSはアプリケーション層とトランスポート層の間で動作
→ アプリケーションを変更せずに暗号化を追加できる

TLSハンドシェイク

TLS接続確立時に行われる鍵交換と認証のプロセスです。

TLS 1.2 ハンドシェイク

クライアント                              サーバー
│ │
│ ──── 1. ClientHello ────────────────→ │
│ ・対応TLSバージョン │
│ ・対応暗号スイート一覧 │
│ ・クライアントランダム値 │
│ │
│ ←──── 2. ServerHello ─────────────── │
│ ・選択したTLSバージョン │
│ ・選択した暗号スイート │
│ ・サーバーランダム値 │
│ │
│ ←──── 3. Certificate ─────────────── │
│ ・サーバー証明書 │
│ │
│ ←──── 4. ServerKeyExchange ───────── │
│ ・鍵交換パラメータ(DH/ECDH) │
│ │
│ ←──── 5. ServerHelloDone ─────────── │
│ │
│ ──── 6. ClientKeyExchange ──────────→ │
│ ・クライアントの鍵交換データ │
│ │
│ ──── 7. ChangeCipherSpec ───────────→ │
│ ・「これ以降は暗号化します」 │
│ │
│ ──── 8. Finished (暗号化) ──────────→ │
│ │
│ ←──── 9. ChangeCipherSpec ────────── │
│ ←──── 10. Finished (暗号化) ───────── │
│ │
│ ←════ 暗号化通信開始 ════════════════→ │

TLS 1.3 ハンドシェイク(高速化)

TLS 1.3では往復回数が削減された(1-RTT):

クライアント サーバー
│ │
│ ──── ClientHello + KeyShare ────────→ │
│ ・対応暗号スイート │
│ ・鍵交換データ(先に送信) │
│ │
│ ←──── ServerHello + KeyShare ─────── │
│ ←──── EncryptedExtensions ────────── │
│ ←──── Certificate ────────────────── │
│ ←──── CertificateVerify ──────────── │
│ ←──── Finished ───────────────────── │
│ │
│ ──── Finished ──────────────────────→ │
│ │
│ ←════ 暗号化通信開始 ════════════════→ │

改善点:
- 往復回数: 2-RTT → 1-RTT
- 0-RTT再接続(セッション再開時)
- 古い暗号方式の廃止

暗号スイート

TLSで使用する暗号アルゴリズムの組み合わせです。

暗号スイートの構成

例: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
│ │ │ │ │ │
│ │ │ │ │ └── PRF/HMAC用ハッシュ
│ │ │ │ └─────── 認証付き暗号モード
│ │ │ └─────────── 鍵長(ビット)
│ │ └──────────────── 暗号化アルゴリズム
│ └───────────────────────── 認証アルゴリズム
└──────────────────────────────── 鍵交換アルゴリズム

各要素の役割:
┌─────────────────────────────────────────────────────────────┐
│ 要素 │ 例 │ 役割 │
├─────────────────────────────────────────────────────────────┤
│ 鍵交換 │ ECDHE │ セッション鍵の共有 │
│ 認証 │ RSA │ サーバー証明書の署名検証 │
│ 暗号化 │ AES_256 │ データの暗号化 │
│ モード │ GCM │ 認証付き暗号化 │
│ ハッシュ │ SHA384 │ 完全性検証 │
└─────────────────────────────────────────────────────────────┘

TLS 1.3 の暗号スイート

TLS 1.3では暗号スイートが簡略化:

┌─────────────────────────────────────────────────────────────┐
│ TLS 1.3 暗号スイート │
├─────────────────────────────────────────────────────────────┤
│ TLS_AES_256_GCM_SHA384 │ 推奨(最も安全) │
│ TLS_AES_128_GCM_SHA256 │ 推奨 │
│ TLS_CHACHA20_POLY1305_SHA256 │ モバイル向け(高速) │
└─────────────────────────────────────────────────────────────┘

TLS 1.3の変更点:
- 鍵交換は常にECDHEまたはDHE(前方秘匿性を強制)
- RSA鍵交換は廃止
- 認証は別途ネゴシエーション

推奨暗号スイート

セキュリティレベル別の推奨:

【高セキュリティ(金融・医療等)】
優先順位:
1. TLS_AES_256_GCM_SHA384 (TLS 1.3)
2. TLS_CHACHA20_POLY1305_SHA256 (TLS 1.3)
3. TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (TLS 1.2)

【標準セキュリティ】
1. TLS_AES_128_GCM_SHA256 (TLS 1.3)
2. TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (TLS 1.2)

【避けるべき暗号スイート】
✗ RC4を含むもの(脆弱)
✗ DESまたは3DESを含むもの(脆弱)
✗ MD5を含むもの(脆弱)
✗ 輸出グレード(EXPORT)暗号
✗ NULL暗号(暗号化なし)
✗ RSA鍵交換(前方秘匿性なし)

前方秘匿性(Forward Secrecy)

前方秘匿性とは

前方秘匿性(Perfect Forward Secrecy / PFS):

秘密鍵が将来漏洩しても、過去の通信は復号できない

【前方秘匿性なし(RSA鍵交換)】
┌─────────────────────────────────────────────────────────────┐
│ クライアント サーバー │
│ │ │ │
│ │ ──プリマスターシークレット──→ │ │
│ │ (サーバーの公開鍵で暗号化) │ │
│ │ │ │
│ もしサーバーの秘密鍵が漏洩したら... │
│ → 過去に記録された通信も全て復号可能! │
└─────────────────────────────────────────────────────────────┘

【前方秘匿性あり(ECDHE鍵交換)】
┌─────────────────────────────────────────────────────────────┐
│ クライアント サーバー │
│ │ │ │
│ │ ← 一時的なECDH公開鍵を交換 → │ │
│ │ (セッションごとに異なる鍵ペア) │ │
│ │ │ │
│ サーバーの長期秘密鍵が漏洩しても... │
│ → 各セッションの一時鍵は既に破棄済み │
│ → 過去の通信は復号不可能! │
└─────────────────────────────────────────────────────────────┘

前方秘匿性の確保

前方秘匿性を確保するための設定:

✓ ECDHE または DHE 鍵交換を使用
✓ RSA鍵交換を無効化
✓ TLS 1.3 を優先(強制的にPFS)

Nginx設定例:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers on;

証明書の検証

TLSでは証明書を使ってサーバーの身元を確認します。

検証プロセス

証明書検証の流れ:

1. 証明書チェーンの検証
┌─────────────────┐
│ ルートCA証明書 │ ← ブラウザ/OSに事前インストール
│ (信頼のアンカー) │
└────────┬────────┘
│ 署名
┌────────┴────────┐
│ 中間CA証明書 │
└────────┬────────┘
│ 署名
┌────────┴────────┐
│ サーバー証明書 │ ← サーバーから送信
└─────────────────┘

2. 有効期限の確認
現在時刻が notBefore と notAfter の間にあるか

3. 失効確認
CRL(証明書失効リスト)またはOCSPで確認

4. ホスト名の検証
証明書のCN(Common Name)または SAN(Subject Alternative Name)が
接続先のホスト名と一致するか

証明書の種類

証明書の検証レベル:

┌─────────────────────────────────────────────────────────────┐
│ 種類 │ 検証内容 │ 用途 │
├─────────────────────────────────────────────────────────────┤
│ DV │ ドメイン所有権のみ │ 個人サイト、ブログ │
│ (Domain │ 自動発行可能 │ Let's Encrypt等 │
│ Valid) │ │ │
├─────────────────────────────────────────────────────────────┤
│ OV │ + 組織の実在確認 │ 企業サイト │
│ (Org │ 電話確認等が必要 │ │
│ Valid) │ │ │
├─────────────────────────────────────────────────────────────┤
│ EV │ + 厳格な組織審査 │ 金融機関、ECサイト │
│ (Ext │ 法的書類の確認 │ (アドレスバーに組織名) │
│ Valid) │ │ │
└─────────────────────────────────────────────────────────────┘

TLS設定のベストプラクティス

サーバー設定

Nginx TLS設定例:

server {
listen 443 ssl http2;
server_name example.com;

# 証明書
ssl_certificate /etc/ssl/certs/example.com.crt;
ssl_certificate_key /etc/ssl/private/example.com.key;

# プロトコル
ssl_protocols TLSv1.2 TLSv1.3;

# 暗号スイート
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';

# サーバー側で暗号スイートを選択
ssl_prefer_server_ciphers on;

# セッションキャッシュ
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;

# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;

# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}

セキュリティヘッダー

重要なHTTPヘッダー:

1. HSTS(HTTP Strict Transport Security)
Strict-Transport-Security: max-age=31536000; includeSubDomains
→ ブラウザに「常にHTTPSを使用」と指示

2. CSP(Content Security Policy)
→ XSS対策、リソース読み込み制限

3. X-Content-Type-Options
X-Content-Type-Options: nosniff
→ MIMEタイプスニッフィング防止

TLSのトラブルシューティング

よくある問題

┌─────────────────────────────────────────────────────────────┐
│ エラー │ 原因と対策 │
├─────────────────────────────────────────────────────────────┤
│ 証明書の有効期限切れ │ 証明書を更新 │
│ │ Let's Encryptなら自動更新設定 │
├─────────────────────────────────────────────────────────────┤
│ 証明書のホスト名不一致 │ CNまたはSANにホスト名を追加 │
│ │ ワイルドカード証明書を検討 │
├─────────────────────────────────────────────────────────────┤
│ 中間証明書が不足 │ 証明書チェーンを正しく設定 │
│ │ サーバー証明書 + 中間証明書 │
├─────────────────────────────────────────────────────────────┤
│ 暗号スイートの不一致 │ サーバーとクライアントで │
│ │ 共通の暗号スイートを設定 │
├─────────────────────────────────────────────────────────────┤
│ 古いTLSバージョン │ TLS 1.2以上を使用 │
│ │ TLS 1.0/1.1は廃止済み │
└─────────────────────────────────────────────────────────────┘

診断ツール

TLS設定の確認方法:

1. OpenSSLコマンド
openssl s_client -connect example.com:443 -tls1_2
openssl s_client -connect example.com:443 -tls1_3

2. 証明書の確認
openssl x509 -in cert.pem -text -noout

3. オンラインツール
- SSL Labs (ssllabs.com/ssltest)
- testssl.sh

4. curl での確認
curl -v https://example.com
curl --tlsv1.3 https://example.com

IDサービスでのTLS

要件

IDサービス(OAuth/OIDC)でのTLS要件:

┌─────────────────────────────────────────────────────────────┐
│ 必須要件 │
├─────────────────────────────────────────────────────────────┤
│ ・全てのエンドポイントでHTTPS必須 │
│ - 認可エンドポイント │
│ - トークンエンドポイント │
│ - ユーザー情報エンドポイント │
│ │
│ ・TLS 1.2以上 │
│ │
│ ・信頼された認証局(CA)からの証明書 │
│ - 自己署名証明書は本番環境で使用不可 │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│ FAPI(金融グレード)追加要件 │
├─────────────────────────────────────────────────────────────┤
│ ・TLS 1.2以上(TLS 1.3推奨) │
│ ・前方秘匿性(PFS)必須 │
│ ・相互TLS(mTLS)のサポート │
│ ・証明書バインドトークン │
└─────────────────────────────────────────────────────────────┘

mTLS(相互TLS認証)

mTLS(Mutual TLS):

通常のTLS:
クライアント ← サーバー証明書を検証

mTLS:
クライアント ← サーバー証明書を検証
クライアント証明書 → サーバーが検証

┌─────────────────────────────────────────────────────────────┐
│ クライアント サーバー │
│ │ │ │
│ │ ←── サーバー証明書 ──────────────── │ │
│ │ (サーバーの身元確認) │ │
│ │ │ │
│ │ ─── クライアント証明書 ───────────→ │ │
│ │ (クライアントの身元確認) │ │
│ │ │ │
│ │ ←════ 双方向認証完了 ══════════════→ │ │
└─────────────────────────────────────────────────────────────┘

用途:
- OAuth 2.0 トークンエンドポイントのクライアント認証
- 証明書バインドアクセストークン
- APIのマシン間認証

まとめ

TLS/SSL の重要ポイント:

1. TLS 1.2以上を使用(TLS 1.3推奨)
- TLS 1.0/1.1は廃止済み

2. 前方秘匿性(PFS)を確保
- ECDHE鍵交換を使用
- RSA鍵交換は避ける

3. 適切な暗号スイートを選択
- AES-GCM推奨
- 脆弱な暗号を無効化

4. 証明書を正しく管理
- 有効期限の監視
- 証明書チェーンの設定
- OCSP Staplingの有効化

5. セキュリティヘッダーを設定
- HSTS
- その他のセキュリティヘッダー

次のステップ