HTTPSとTLSの仕組みを徹底解説:ステップバイステップガイド
ブラウザの鍵アイコンを見て、接続は安全だと思ったことはありませんか?しかし、HTTPSサイトにアクセスしたとき実際に何が起きているのでしょうか?ブラウザはどうやって本物のサーバーと通信していると確認するのでしょうか?そして、TLSがサイトを遅くすることがあるのはなぜでしょうか?
このガイドでは、ハンドシェイクをステップバイステップで説明し、HTTPSとTLSの謎を解き明かします。証明書の役割、共通鍵暗号と公開鍵暗号、そして自分のプロジェクトでTLSを検証・最適化する方法を学びましょう。
HTTPSとTLSが実際に行うこと
HTTPSは、TLS(Transport Layer Security)上にHTTPを重ねたものです。TLSは次の3つの保証を提供します:
- 機密性:データは暗号化され、盗聴者は読めません。
- 完全性:データは転送中に検出されずに変更されることはありません。
- 認証:攻撃者ではなく、正規のサーバーと通信しています。
TLSがなければ、HTTPトラフィックは平文で送信されます。ネットワーク経路上の誰でも(Wi-Fiホットスポット、ISP、侵害されたルーター)読み取ったり改ざんしたりできます。TLSは、HTTPデータが交換される前に安全なチャネルを確立することでこれを解決します。
TLSハンドシェイク:ステップバイステップ
ハンドシェイクは魔法が起こる場所です。共有鍵を確立し、身元を検証するネゴシエーションです。以下はTLS 1.2と1.3(現在遭遇する2つのバージョン)の簡略化された流れです。
ステップ1:Client Hello
クライアント(ブラウザ)はClientHelloメッセージを送信します。これには以下が含まれます:
- サポートするTLSバージョン(例:TLS 1.3、TLS 1.2)
- サポートする暗号スイート(アルゴリズムの組み合わせ)
- ランダムなバイト列(クライアントランダム)
- TLS 1.3の場合、Diffie-Hellman交換用の鍵共有
ステップ2:Server Helloと証明書
サーバーはServerHello(選択されたバージョン、暗号スイート、サーバーランダム)とその証明書で応答します。証明書にはサーバーの公開鍵が含まれ、認証局(CA)によって署名されています。
クライアントは証明書を検証します:期限切れではないか?信頼されたCAによって発行されているか?ドメインは一致するか?そうでなければ、ブラウザは警告を表示します。
ステップ3:鍵交換
サーバーの公開鍵(またはDiffie-Hellmanパラメータ)を使用して、クライアントとサーバーは共有のプリマスターシークレットを導出します。TLS 1.3では、これは一時的なDiffie-Hellman(ECDHE)で行われ、前方秘匿性を提供します:サーバーの秘密鍵が後で侵害されても、過去のセッションは安全なままです。
ステップ4:Finished
両側は新しく導出された鍵で暗号化されたFinishedメッセージを送信します。復号化が成功すれば、ハンドシェイクは完了です。その後、すべてのアプリケーションデータ(HTTP)は共通鍵暗号(例:AES-GCMやChaCha20-Poly1305)で暗号化されます。
TLS 1.3の改善点
TLS 1.3はハンドシェイクを1ラウンドトリップ(1-RTT)に短縮し、再訪問者向けに0-RTT再開をサポートします。また、古いアルゴリズムを削除し、より高速で安全にしています。ほとんどの最新ブラウザとサーバーはTLS 1.3をサポートしています。
TLSにおける共通鍵暗号と公開鍵暗号
TLSは正当な理由で両方のタイプの暗号化を使用します:
- 公開鍵暗号:ハンドシェイク中にサーバーを認証し、鍵を安全に交換するために使用されます。計算コストは高いですが、鍵配送問題を解決します。
- 共通鍵暗号:ハンドシェイク後の大量データ転送に使用されます。高速で効率的です。
このハイブリッドアプローチにより、公開鍵暗号のセキュリティと共通鍵暗号のパフォーマンスを両立できます。
証明書:信頼のアンカー
証明書は公開鍵をドメイン名に結び付け、CAによって署名されています。ブラウザとオペレーティングシステムには、信頼されたルートCAのストアが同梱されています。サーバーが証明書を提示すると、クライアントは信頼されたルートまでの信頼チェーンを構築します。
証明書には有効期限があります(現在ではLet's Encryptで90日が多い)。期限切れの証明書はブラウザエラーを引き起こすため、更新を自動化しましょう。
実践:OpenSSLでTLSを検査する
opensslコマンドラインツールを使用して、サーバーのTLS設定を検査できます。これはハンドシェイクの失敗をデバッグしたり、暗号スイートを検証したりするのに役立ちます。
openssl s_client -connect example.com:443 -servername example.com -tls1_3
これはサーバーに接続し、証明書チェーン、ネゴシエートされた暗号、セッションの詳細を出力します。証明書が有効であることを確認するには、Verify return code: 0 (ok)を探します。
証明書の有効期限を確認するには:
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | openssl x509 -noout -dates
よくあるTLSの落とし穴と回避策
- 証明書の期限切れ:自動更新と監視を設定しましょう。Let's EncryptにはCertbotなどのツールを使用します。
- 混合コンテンツ:HTTPSページでHTTPリソースを読み込むとセキュリティが破られます。相対URLを使用するか、すべてのリソースがHTTPSであることを確認しましょう。
- 弱い暗号スイート:古いプロトコル(TLS 1.0、1.1)と弱い暗号(RC4、3DES)を無効にしましょう。TLS 1.3を有効にします。
- HSTSの欠如:
Strict-Transport-Securityヘッダーを追加して、将来の訪問でHTTPSを強制しましょう。 - 不完全な証明書チェーン:一部のサーバーは中間証明書を含めるのを忘れ、一部のクライアントでエラーを引き起こします。SSL Labsでテストしましょう。
TLSパフォーマンスの最適化
TLSはハンドシェイクのためにレイテンシを追加します。これを最小限に抑える方法は次のとおりです:
- より高速なハンドシェイクを持つTLS 1.3を有効にします。
- セッション再開(セッションチケットまたは事前共有鍵)を使用して、再訪問者の完全なハンドシェイクを避けます。
- OCSPステープリングを有効にして、証明書検証のレイテンシを削減します。
- エッジでTLS終端を行うCDNを使用して、ラウンドトリップ時間を短縮します。
- 証明書を小さく保ちます(可能な場合はRSAの代わりにECDSAを使用)。
FAQ
HTTPSとTLSの違いは何ですか?
HTTPSはHTTPの安全なバージョンであり、TLSはセキュリティを提供する暗号プロトコルです。HTTPSはTLSを使用して接続を暗号化および認証します。
TLSはどのように前方秘匿性を提供しますか?
前方秘匿性は、サーバーの秘密鍵が侵害されても、過去のセッション鍵を導出できないことを保証します。これはTLS 1.3と最新のTLS 1.2設定で一時的なDiffie-Hellman鍵交換(ECDHE)を使用することで実現されます。
一部のサイトで証明書エラーが表示されるのはなぜですか?
証明書エラーは通常、証明書が期限切れ、自己署名、異なるドメイン用に発行、または証明書チェーンが不完全であることを意味します。ブラウザは中間者攻撃から保護するためにそのような証明書を拒否します。
TLS接続を検査またはデバッグする必要がある場合、Timestamp Converterのようなツールが証明書の有効期間をデコードし、時間関連の問題をデバッグするのに役立ちます。