はじめに
この記事の目的
本記事は、SSL/TLSハンドシェイクについて初心者から中級者向けにわかりやすく解説することを目的としています。技術的な背景がなくても読み進められるよう、専門用語は最小限に抑え、具体例を交えて説明します。
ハンドシェイクとは何か(簡単なイメージ)
ハンドシェイクは、クライアント(例:あなたのブラウザ)とサーバー(例:ウェブサイト)が「安全に話します」と約束するための最初のやり取りです。実生活で鍵を交換して部屋を施錠するイメージで、通信を暗号化するためのルールや鍵を決めます。
本記事で学べること
- ハンドシェイクの役割と仕組みの概略
- TLS 1.2 の代表的な14ステップの流れ(章ごとに詳述します)
- なぜ安全になるのかの理由(認証・暗号方式・共通鍵の共有)
読み方の目安
技術的な章は段階的に進めます。まずは本章で全体像をつかみ、その後で各ステップを順に読むと理解が深まります。必要に応じて実例や図を参照しながら読み進めてください。
SSL/TLSハンドシェイクとは?
概要
SSL/TLSハンドシェイクは、クライアント(例:ブラウザ)とサーバーが暗号化通信を始める前に行う「準備手続き」です。互いの身元を確かめ、どの暗号方式を使うか決め、安全に通信するための共通鍵(セッション鍵)を作ります。これが終わると、アドレスバーに鍵マークや「https://」が表示され、暗号化された通信になります。
主な目的
- サーバーの認証:サーバーが本物か証明書で確認します。例として、銀行のサイトが本当に銀行のものか確かめます。
- 暗号スイートの決定:どの暗号方式を使うか合意します(例:AESやRSAなど)。
- セッション鍵の生成:実際のデータ暗号に使う共通鍵を安全に共有します。
安全にする仕組み(かんたんに)
公開鍵暗号を使って最初のやり取りを安全にし、その後は高速な共通鍵で通信します。公開鍵は誰でも見られますが、秘密鍵だけがサーバーにあります。
なぜ重要か
ハンドシェイクが成功しないと通信は続けられません。正しく行われないと第三者に情報を盗まれたり、なりすましを受ける危険があります。
たとえ話
初対面で身分証を見せ合い、共通の合言葉を決めてから会話を始めるようなものです。
ざっくりとしたハンドシェイクの流れ
ここではSSL/TLSハンドシェイクの大まかな流れをやさしく説明します。細かい仕様は後の章で触れますが、まずは全体像をつかみましょう。
- クライアントが挨拶(Client Hello)を送る
-
対応するプロトコルのバージョンや暗号方式の候補、乱数などを送ります。例えると「こんにちは、こんなやり方で話せますか?」と聞く場面です。
-
サーバーが返答(Server Hello)を送る
-
サーバーは使うバージョンや暗号方式を決め、応答します。
-
サーバーが証明書を提示(Certificate)
-
サーバーの身元を証明する書類を送ります。クライアントは発行者と期限、ドメイン名を確認します。
-
クライアントが鍵の材料を送る(Client Key Exchange)
-
クライアントは共通鍵の元になる値(プリマスターシークレット)をサーバーの公開鍵で暗号化して送るか、鍵共有の仕組みで値を交換します。
-
両者が鍵を作り、確認(Finished)
-
送受信した情報から同じ共有鍵を生成し、ハンドシェイクが正しく終わったことを互いに確かめます。
-
共通鍵での暗号化通信へ
- 以降は生成した共有鍵でデータを暗号化してやり取りします。
※補足:クライアント認証が必要な場合は、クライアント証明書の送信が途中に入ります。
SSL/TLSハンドシェイクの14ステップ(TLS 1.2ベース)
1. Client Hello(クライアント → サーバー)
クライアント(例:ブラウザ)が使える暗号方式やバージョン、乱数を送ります。サーバーに「これが私の候補です」と知らせます。
2. Server Hello(サーバー → クライアント)
サーバーが暗号方式とバージョン、乱数を選んで返します。双方の共通言語がここで決まります。
3. Certificate(サーバー → クライアント)
サーバーは証明書を送ります。証明書で身元(例:サイトの正当性)を確認します。
4. Server Key Exchange(サーバー → クライアント)※必要時
選んだ方式により公開鍵など追加情報を送ります。主に一時鍵交換で使います。
5. Certificate Request(サーバー → クライアント)※オプション
サーバーがクライアント証明書を要求する場合に使います。企業内システムで見られます。
6. Server Hello Done(サーバー → クライアント)
サーバーが送信を終えた合図です。これ以降はクライアントが応答します。
7. Client Certificate(クライアント → サーバー)※オプション
クライアント証明書を送ります。クライアントの身元を証明する場面で使います。
8. Client Key Exchange(クライアント → サーバー)
共通鍵を作るための情報(例:プリマスターシークレット)をサーバーに送ります。これが暗号通信の元になります。
9. Client Verify(クライアント → サーバー)※オプション
クライアント証明書を使う場合、クライアントが署名で認証を示します。
10. Change Cipher Spec(クライアント → サーバー)
これ以降の通信は合意した暗号で行うという宣言を送ります。
11. Finished(クライアント → サーバー)
ハンドシェイクの最初側の完了メッセージです。これでクライアント側は設定が正しいと確認します。
12. Change Cipher Spec(サーバー → クライアント)
サーバーも同様に暗号適用を開始する宣言を返します。
13. Finished(サーバー → クライアント)
サーバー側の完了メッセージです。双方が安全に通信できる状態になります。
14. アプリケーションデータの交換
ハンドシェイク終了後、暗号化された通常のデータ(例:HTTPリクエスト/レスポンス)を送受信します。
① Client Hello(クライアント → サーバー)
クライアントがSSL/TLS通信の開始を告げる最初のメッセージです。ここでクライアントは自分の「できること」を並べ、サーバーに通信ルールの選択を委ねます。
主な内容:
-
プロトコルバージョン
クライアントが使えるTLSの最高バージョンを示します。例: TLS 1.2や1.3。 -
Client Random(乱数+時刻)
32バイト程度の値で、先頭に現在時刻が入ることが多いです。鍵交換やセッション鍵生成の材料になります。 -
サポートする暗号スイート一覧
暗号の組み合わせ(鍵交換法・暗号・ハッシュ)を順に提示します。サーバーはこの中から1つを選びます。具体例: ECDHE_RSA_WITH_AES_128_GCM_SHA256(読み方と意味は後の章で説明します)。 -
圧縮方法一覧
圧縮の有無や方式を列挙します。最近はほとんど「なし」が使われます。 -
セッションID
再接続で同じセッションを使えるようにするための識別子です。新しいセッションなら空にします。 -
拡張(オプション)
SNI(接続先ホスト名)、ALPN(アプリ名指定)、対応曲線など、追加情報を含められます。
この情報を受けてサーバーは相互に使えるルールを決定し、次にServer Helloで応答します。
② Server Hello(サーバー → クライアント)
概要
Server Helloは、クライアントのClient Helloに対するサーバーの返答です。ここでサーバーは「どのルールで通信するか」を決めて伝えます。以後のやりとりで使う乱数や暗号方式、セッション情報などが含まれます。
主なフィールドと意味
-
TLSバージョン
サーバーが採用するプロトコルのバージョンを示します。クライアントが提示した範囲からサーバー側が選びます。 -
Server Random(サーバーランダム)
32バイトの乱数で、最初の4バイトに現在時刻(秒)が入ることが多いです。クライアントランダムと組み合わせて鍵を作る材料になります。 -
暗号スイート(Cipher Suite)
サーバーがクライアントの候補から一つ選びます。例えば「鍵交換はECDHE、暗号はAES、認証はRSA」のように通信の方式を決定します。 -
圧縮方式
通常は圧縮なし(null)を選びます。古い方式はセキュリティ上の問題で使われません。 -
セッションID
セッション再開に使う識別子です。クライアントが以前のセッションIDを送っていれば、サーバーが同じIDを返すことで再接続を短縮できます。 -
拡張情報
サーバーは必要に応じて拡張を返します(例:応答するTLS拡張の種類)。これにより追加機能が有効になります。
実務的なポイント
サーバーはクライアントの提示をすべて受け入れるわけではありません。互換性やセキュリティ方針に基づき最適な設定を選びます。選択結果は以後の鍵生成や通信暗号化に直接影響しますので、ここで決まった内容を両者が正しく使うことが大切です。
③ Certificate(サーバー → クライアント)
送信されるもの
サーバーはサーバー証明書をクライアントに送ります。証明書には主に次が含まれます:ドメイン名(例: www.example.com)、公開鍵、発行者(CA)の情報、有効期間、発行者のデジタル署名。
証明書の意味
証明書は「このサーバーの身元をCAが確認しました」という電子的な身分証です。公開鍵は後で暗号通信を始めるために使います。署名は証明書が改ざんされていないことを保証します。
クライアントの検証手順
- ドメイン照合:証明書に書かれたドメインが接続先と一致するか確認します(例: www.example.com)。
- 有効期限確認:現在日時が有効期間内かをチェックします。
- 署名検証:証明書の署名を発行者(CA)の公開鍵で検証し、改ざんがないか確かめます。
- 信頼連鎖確認:中間CAを含め、最終的に信頼済みルートCAまでつながるか確認します。
- 失効確認(任意だが重要):CRLやOCSPで失効情報を確認します。
証明書チェーン
サーバーは中間CA証明書も一緒に送ることが多いです。クライアントはそれらを使って信頼できるルートCAまでつなげます。
検証に失敗したら
検証に失敗するとブラウザは警告を出し、多くの場合接続を中止します。自己署名証明書や期限切れ、ドメイン不一致がよくある原因です。
④ Server Key Exchange(サーバー → クライアント)※必要に応じて
目的
暗号スイートが(E)DHEなどの一時的な鍵交換を使う場合、サーバーは追加の鍵交換情報を送ってクライアントと共有秘密を作ります。これにより前向き秘匿性(Forward Secrecy)を実現できます。
送信される情報
- DHE: DHのパラメータ(素数p、生成元g)とサーバーの公開値(g^b)
- ECDHE: 使用する楕円曲線の識別子とサーバーの公開点(曲線上の点)
暗号スイートがRSA鍵交換でサーバー証明書に公開鍵が含まれる場合は、このメッセージは省略されます。
署名と検証
サーバーはこれらのパラメータに対して署名を付け、証明書に対応する秘密鍵で署名します。クライアントは証明書の公開鍵で署名を検証し、パラメータ改ざんを防ぎます。
クライアント側の処理
クライアントは受け取ったパラメータを使い自分の公開値を計算してClient Key Exchangeで送ります。双方が計算した共有秘密からセッション鍵を導出します。
注意点
署名がない場合や検証に失敗した場合は接続を中断します。これにより中間者攻撃を防ぎます。
⑤ Certificate Request(サーバー → クライアント)※オプション
概要
サーバーがクライアントに対して「あなたの証明書を出してください」と頼むメッセージです。クライアント認証(相互TLS)を行う場合に送られます。銀行のオンラインサービスや企業の社内システムでよく使われます。
サーバーが示す内容
サーバーは、おおまかに次を伝えます。
– 受け入れる証明書の種類(例:RSA、ECDSA)
– 受け入れる認証局(CA)のリスト
– 使ってほしい署名方式
これらを見てクライアントは自分の証明書が合うか判断します。
クライアントの動作
クライアントは条件に合う証明書を持っていればClient Certificateメッセージで送ります。持っていなければ空のCertificateを送るか、サーバー規約によっては接続を断られます。したがって、証明書が必要なサービスでは事前に配布と設定が重要です。
使われる具体例
- 銀行の重要操作で二要素の一つとしてクライアント証明書を要求
- 企業のVPNや社内ポータルで社員証明書を使った認証
注意点
秘密鍵はクライアント側で厳重に保護する必要があります。証明書管理(有効期限、失効)を怠ると正常な接続ができなくなります。相互TLSはセキュリティを高めますが、導入と運用に手間がかかります。
⑥ Server Hello Done(サーバー → クライアント)
役割
Server Hello Done は、サーバーがハンドシェイクの最初の送信をすべて終えたことをクライアントに伝える短いメッセージです。料理で例えると、シェフが「前菜とメインの準備が整いました」と合図するようなものです。これ以降、サーバーからの初期メッセージはもう来ません。
具体的に何を意味するか
サーバーはすでに Server Hello、証明書(Certificate)、必要なら Server Key Exchange や Certificate Request を送り終えています。Server Hello Done はそれらの完了を明確に区切る合図です。クライアントはこの合図を受け取り、次の自分の役割に移ります。
クライアント側の次のステップ
クライアントはここで自分の証明書を送るかどうか判断します(Certificate Request があれば Client Certificate を送ります)。その後、Client Key Exchange、必要なら Client Verify を送り、鍵共有の準備を進めます。短いですが重要な区切りのメッセージです。
トラブル時の挙動
もしサーバーのメッセージに不備があれば、クライアントはアラートを返してハンドシェイクを中止します。またタイミングの問題でメッセージが欠けると接続は失敗します。簡潔な合図ですが、正確さが求められます。
⑦ Client Certificate(クライアント → サーバー)※オプション
概要
Certificate Requestをサーバーが送った場合、クライアントは自分のクライアント証明書を送ります。これはクライアント側の身分証明書のようなもので、サーバー側がクライアントを信頼できるかどうか判断するために使います。
クライアントが送るもの
クライアント証明書には公開鍵と所有者情報(例:氏名や組織名)が含まれ、認証局(CA)の署名で信頼性が付与されています。クライアントはこれをサーバーに送付し、対応する秘密鍵で後続の署名を行います。
サーバー側の検証
サーバーは受け取った証明書の有効期限、CAによる署名、証明書チェーン、失効情報(CRLやOCSP)などを確認します。照合が成功すると、サーバーは接続をそのクライアントの特定のユーザーやデバイスに紐づけます。失敗した場合は接続を拒否するか、クライアント認証を必須にしていればハンドシェイクを中断します。
実際の使われ方(例)
金融機関や社内システムで相互TLS(mutual TLS)が使われます。ユーザーはあらかじめ発行されたクライアント証明書をブラウザやデバイスに導入し、サイトはそれで本人確認を行います。
注意点
クライアント証明書の秘密鍵は厳重に保護してください。盗まれるとなりすましに使われます。証明書の配布・失効管理を適切に行うことが重要です。
⑧ Client Key Exchange(クライアント → サーバー)
目的
クライアントは共通鍵(セッション鍵)の元になる「プリマスターシークレット」をサーバーと安全に共有します。これで以降の通信を対称暗号で効率よく暗号化できます。
処理の流れ
- クライアントがプリマスターシークレットを生成します(ランダムな値)。
- サーバーの公開鍵でその値を暗号化し、Client Key Exchangeメッセージで送ります。
- サーバーは自分の秘密鍵で復号し、同じプリマスターシークレットを得ます。
具体例(RSAの場合)
クライアントはランダム値を作り、サーバー証明書に含まれる公開鍵で暗号化します。サーバーは秘密鍵で復号してプリマスターシークレットを取り出します。両者はこの値からマスターシークレットと対称鍵を導出します。
別の方法:Diffie-Hellman(前方秘匿)
サーバーがDHパラメータを提示している場合、クライアントは自分のDH公開値を送り、双方で共有鍵を計算します。これにより秘密鍵漏洩時でも過去の通信が守られる「前方秘匿(Forward Secrecy)」を得られます。
サーバー側の処理と鍵生成
サーバーは受け取った情報からプリマスターシークレットを復元し、クライアントと同じ手順でマスターシークレットと対称鍵を作ります。以降の通信はこの対称鍵で暗号化・整合性検証します。
注意点
- RSA方式ではサーバー秘密鍵の管理が鍵です。
- DH系では鍵交換のパラメータ検証が重要です。
以上がClient Key Exchangeの要点です。
⑨ Client Verify(クライアント → サーバー)※オプション
目的
クライアントが本当に自分の秘密鍵を持っていることをサーバーに証明します。サーバーがクライアント証明書の所有者を確認できるようにするためのメッセージです。
送信タイミング
サーバーがクライアント証明書を要求した場合にのみ送ります。通常、Client Key Exchange の後に続きます。
送信内容(簡単に)
クライアントはこれまでのハンドシェイクメッセージのハッシュを作り、自分の秘密鍵でデジタル署名します。その署名を CertificateVerify メッセージとして送信します。署名方式は RSA、DSA、ECDSA など、交渉で決まった方式を使います。
サーバー側の検証手順
サーバーはクライアントが以前に送った証明書から公開鍵を取り出します。その公開鍵で署名を検証し、ハッシュが一致すればクライアントが秘密鍵を所有していると判断します。検証に失敗すればハンドシェイクを中断します。
なぜ重要か
証明書だけでは秘密鍵の所有が分かりません。CertificateVerify により、証明書と実際の鍵が一致することを確かめられます。これによりなりすましや中間者攻撃のリスクを減らします。
注意点
- クライアント証明書を使わない場合はこのメッセージは送られません。
- サーバーは証明書の有効性(信頼できる発行者か、有効期限、失効など)も確認します。












