徹底解説:SSL/TLSハンドシェイクの仕組みと実践的対策

はじめに

SSL/TLSハンドシェイクは、インターネット上で安全に通信を行うための初期手続きです。ハンドシェイクを通じてクライアントとサーバは暗号方式の合意、認証、暗号鍵の共有を行い、その後の通信を暗号化します。本コラムではTLSのバージョン差、各メッセージの意味、鍵導出の仕組み、セッション再開や0-RTT、実装や運用上の注意点、代表的な脆弱性とその対策まで、可能な限り詳細に解説します。

TLSのバージョンと設計思想の変化

TLSは歴史的に進化してきました。主な節目はTLS 1.0/1.1、TLS 1.2、TLS 1.3です。TLS 1.2まではハンドシェイクで多様な鍵交換方式(RSA、DH、ECDHEなど)や暗号/MACの組合せが選べました。TLS 1.3では設計が簡素化され、より安全で高速になるように次が導入されています。

  • 不要な暗号方式や脆弱な機能の削除(例:静的RSA鍵交換の廃止、暗号スイート内の個別MACの廃止)
  • 初期接続でのラウンドトリップ数削減(0-RTTの導入により一部の再接続でデータ送信を短縮)
  • HKDFに基づく鍵導出、AEAD暗号の必須化(AES-GCM、ChaCha20-Poly1305など)

TLS 1.2以前の典型的ハンドシェイク(フルハンドシェイク)

TLS 1.2におけるフルハンドシェイクの主要メッセージ順は以下の通りです。ここでは代表的なRSA/ECDHEを含む場合を説明します。

  • ClientHello:クライアントがサポートするプロトコルバージョン、乱数、サポート暗号スイート、拡張(SNI、ALPNなど)を送信
  • ServerHello:サーバが選択したプロトコルバージョン、暗号スイート、乱数を返す
  • Certificate:サーバ証明書チェーンの送信。公開鍵と識別情報を提供
  • ServerKeyExchange(必要な場合):DH/ECDHのパラメータやその署名など鍵交換に必要な追加データを送る
  • CertificateRequest(任意):クライアント認証が必要ならクライアントに要求
  • ServerHelloDone:サーバ側のハンドシェイクメッセージ終了
  • ClientKeyExchange:クライアント側の鍵交換データ(RSAならプレマスターシークレットの暗号化、ECDHEならクライアントキー共有)
  • CertificateVerify(クライアント証明書利用時):クライアントが所持する秘密鍵で署名を行い認証
  • ChangeCipherSpec:以降のメッセージを暗号化する旨を通知
  • Finished:ハンドシェイク全体の検証用ハッシュを送信(暗号化済み)。双方がFinishedを確認できればハンドシェイク完了

この後、アプリケーションデータはTLSレコードプロトコルで暗号化・送受信されます。

TLS 1.3でのハンドシェイクの違いと流れ

TLS 1.3はメッセージ数を削り、暗号設計を安全にしました。代表的な流れは以下です。

  • ClientHello:サポートするバージョン、乱数、暗号スイート、KeyShare(クライアント側のEphemeral鍵)やPSK情報、拡張を含む
  • ServerHello:選択したKeyShareと暗号を返す。以降は暗号化が早く始まる
  • EncryptedExtensions:追加の拡張情報を暗号化して送る
  • Certificate / CertificateVerify:サーバ証明書と署名のやり取り(暗号化済み)
  • Finished:双方でFinishedを交換してハンドシェイク完了

TLS 1.3では鍵共有がClientHelloに含まれることでラウンドトリップが減り、既存のセッションを使うPSK再開では0-RTTデータが可能になります。ただし0-RTTは再送攻撃やリプレイのリスクがあるため用途に応じた注意が必要です。

鍵導出と暗号アルゴリズム

TLS 1.3ではHKDF(HMACを用いた鍵導出関数)により初期シークレットから一連の鍵を派生します。セッション鍵はAEADによって保護され、MACと暗号が分離された古い方式とは異なります。代表的なAEADは以下です。

  • AES-GCM(ハードウェア支援で高速)
  • ChaCha20-Poly1305(モバイルやCPUで有効)

TLS 1.2ではRSA鍵交換や非恒久的なECDHEを使えますが、現在は前方秘匿性を確保するためにECDHEが推奨されます。TLS 1.3では恒久的RSA鍵交換は廃止され、前方秘匿性がデフォルトになっています。

証明書検証と信頼チェーン

サーバは証明書チェーンを提供し、クライアントは以下を検証します。

  • 署名が検証可能か(チェーンとルートCAの存在)
  • 証明書の有効期間
  • 証明書の用途(TLSサーバ認証)
  • ホスト名照合(SNIと比較)
  • 失効情報の確認(CRL、OCSP、OCSP Staplingの利用が推奨)

OCSP StaplingはサーバがOCSPレスポンスを証明書とともに送る仕組みで、レスポンスの改ざん防止やプライバシー向上に有効です。

セッション再開・PSK・0-RTT

ハンドシェイクのコストを下げる手法としてセッション再開があります。主に次の方式があります。

  • セッション ID ベース(古い方式)
  • セッションチケット(Session Ticket) / PSK(TLS 1.3では重要)
  • 0-RTT(TLS 1.3):再接続時に事前共有鍵で早期にデータ送信が可能。ただしリプレイ保護が限定的なため副作用を考慮した設計が必要

0-RTTは性能上のメリットが大きい一方で、同じ0-RTTデータが再送される可能性があるため、非冪等な操作(金融トランザクションなど)には注意して適用する必要があります。

実装と運用上の注意点

安全かつパフォーマンスの高いTLS運用には以下が重要です。

  • TLS 1.3をサポートし、TLS 1.0/1.1や古い弱い暗号は無効化する
  • 前方秘匿性(ECDHEなど)を有効にし、静的RSA鍵交換は避ける
  • 強力な証明書(信頼できるCA、適切な鍵長、短めの有効期間)を使う
  • OCSP Stapling、HSTS、ALPNの適用で安全性とユーザ体験を向上させる
  • ライブラリの更新を継続する(OpenSSL、BoringSSL、LibreSSL、GnuTLS等の脆弱性対応)
  • セキュリティヘッダやログの監視、定期的な脆弱性スキャンを行う

代表的な脆弱性とその対策

過去の代表的な問題と対策をまとめます。

  • Heartbleed(OpenSSLのバッファオーバーラン):ライブラリ更新と秘密鍵のローテーション
  • POODLE/SSLv3脆弱性:SSLv3の無効化
  • BEAST:クライアントとサーバのアップデートと適切な暗号優先順位で緩和
  • Sweet32:3DESなどブロック暗号の古いモードを無効化
  • 中間者(MitM)対策:HSTS、証明書ピンニングの検討、OCSP Stapling

常に最新のエコシステム情報を追い、攻撃手法の変化に応じた設定変更とライブラリ更新を行うことが重要です。

相互認証(mTLS)について

クライアント証明書を用いる相互TLS(mTLS)は、サーバがクライアントの本人性を証明する必要がある環境で有効です。IoTや内部API、マイクロサービス間通信などで採用されます。導入時は証明書配布・失効管理の仕組みが運用上の課題になります。

まとめと推奨事項

TLSハンドシェイクは通信のセキュリティを確保する重要なプロセスです。実務では以下を推奨します。

  • TLS 1.3 を有効にし、古いバージョンと弱い暗号を無効化する
  • 前方秘匿性を確保するためECDHEやTLS 1.3の鍵共有を利用する
  • OCSP Stapling、HSTS、ALPNなどの拡張を適切に設定する
  • 0-RTTを使う場合はリプレイのリスクを設計でカバーする
  • ライブラリや証明書の管理、定期的なスキャンと監査を行う

これらを実践することで、性能と安全性のバランスを保ちながら堅牢なTLS運用が可能になります。

参考文献