HTTPSとTLSの仕組みを徹底解説:内部動作を理解する
URLを入力してEnterキーを押すと、南京錠のアイコンが表示されます。しかし、ブラウザとサーバーの間でその接続を安全にするために実際に何が起こっているのでしょうか?多くの開発者はHTTPSをブラックボックスとして扱います—証明書エラーやパフォーマンスの問題など、何かが壊れるまで。この記事では、HTTPSとTLSの舞台裏を明らかにし、ハンドシェイク、暗号化、証明書検証を実用的な観点から説明します。
HTTPSの正体
HTTPSは、TLS(Transport Layer Security)の上にHTTPを重ねたものです。TLSは次の3つの保証を提供します:
- 機密性: データは暗号化され、盗聴者は読めません。
- 完全性: データは転送中に検出されずに変更されることはありません。
- 認証: 偽装者ではなく、本物のサーバーと通信しています。
TLSはSSL(Secure Sockets Layer)から進化しました。最新バージョン(TLS 1.2および1.3)を使用すべきです。SSLは非推奨です。
TLSハンドシェイク:ステップバイステップ
HTTPデータが流れる前に、クライアントとサーバーは暗号化キーに合意するためにハンドシェイクを行います。典型的なTLS 1.3ハンドシェイク(簡略化)で何が起こるか:
- Client Hello: ブラウザはサポートする暗号スイートのリスト、ランダム値、鍵交換用の鍵シェアを送信します。
- Server Hello: サーバーは暗号スイートを選択し、自身のランダム値と鍵シェアを送信し、証明書を提示します。
- 鍵導出: 両側はDiffie-Hellman鍵交換を使用して同じ共有秘密を計算します。これから、対称暗号化用のセッションキーを導出します。
- Finished: 両当事者はハンドシェイクの完全性を検証するためにMAC(メッセージ認証コード)を送信します。暗号化されたアプリケーションデータが流れるようになります。
TLS 1.3はハンドシェイクを1ラウンドトリップ(1-RTT)に短縮し、再開されたセッションでは0-RTTもサポートするため、レイテンシが改善されます。
鍵交換:Diffie-Hellman
現代のTLSの魔法は、クライアントとサーバーが共有秘密を一度も送信せずに合意できることです。Diffie-Hellman(具体的には楕円曲線用のECDHE)がこれを可能にします。攻撃者がハンドシェイク全体を記録しても、セッションキーを導出することはできません—この特性は前方秘匿性と呼ばれます。
対称暗号化:AESまたはChaCha20
共有秘密が確立されると、TLSは対称暗号化(AES-GCMやChaCha20-Poly1305など)に切り替えます。これは非対称暗号よりもはるかに高速だからです。セッションキーはすべてのアプリケーションデータの暗号化に使用されます。
証明書検証:信頼するが検証する
サーバーの証明書は認証の中心です。これにはサーバーの公開鍵が含まれ、認証局(CA)によって署名されています。ブラウザがそれを検証する方法は次のとおりです:
- 信頼の連鎖: 証明書は、ブラウザまたはOSに事前インストールされている信頼されたルートCAまで連鎖する必要があります。
- ホスト名の一致: 証明書は、訪問しているドメインに対して有効でなければなりません(Subject Alternative Names経由)。
- 有効期間: 証明書は期限切れでなく、まだ有効でないものでもありません。
- 失効: ブラウザはOCSPまたはCRLをチェックして、証明書が失効していないことを確認する場合があります。
いずれかのチェックが失敗すると、「この接続はプライベートではありません」などの警告が表示されます。
よくあるTLSの設定ミス
HTTPSが有効であっても、ミスはセキュリティを弱める可能性があります:
- 古いプロトコル: TLS 1.0/1.1またはSSLv3をサポートすると、既知の攻撃にさらされます。
- 弱い暗号スイート: 対策なしでRC4やCBCモードの暗号を許可する。
- HSTSの欠如: HTTP Strict Transport Securityがないと、ユーザーはHTTPにダウングレードされる可能性があります。
- 証明書の管理不備: 期限切れの証明書や不適切なチェーン設定。
SSL LabsのSSL Testなどのツールを使用して設定を確認してください。
実践例:NginxでHTTPSを有効にする
安全なHTTPSサーバー用の最小限のNginx設定は次のとおりです:
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers off;
add_header Strict-Transport-Security "max-age=63072000" always;
location / {
root /var/www/html;
index index.html;
}
}
この設定はLet's Encrypt証明書を使用し、TLS 1.2と1.3のみを有効にし、HSTSを設定します。
FAQ
TLSとSSLの違いは何ですか?
TLSはSSLの後継です。SSLバージョン(2.0、3.0)はセキュリティ上の欠陥により非推奨です。人々が「SSL証明書」と言うとき、通常はTLS証明書を意味します。
HTTPSはウェブサイトを遅くしますか?
現代のTLS(1.3)は最小限のレイテンシを追加するだけです—多くの場合、わずか数ミリ秒です。セッション再開とHTTP/2により、HTTPSはHTTPと同じかそれ以上に高速になります。
無料のTLS証明書を取得するにはどうすればよいですか?
Let's Encryptは無料の自動化された証明書を提供しています。Certbotなどのツールが取得と更新を行います。
結論
HTTPSとTLSは魔法ではありません—認証用の公開鍵暗号と速度のための対称暗号化を組み合わせた、よく設計されたプロトコルです。ハンドシェイクと証明書検証を理解することで、問題のデバッグやサーバーの安全な設定が可能になります。常にTLS 1.2または1.3を使用し、証明書を最新の状態に保ち、HSTSを有効にしてください。
TLSエラーやパフォーマンスの問題を特定するためにサーバーログを分析するには、Nginx Log Analyzerをお試しください。