HTTPS・TLS

HTTPS・TLSとは

HTTPSは、[[HTTP]] を TLS(Transport Layer Security) で暗号化した通信方式です。URLが https:// で始まり、ブラウザに鍵マークが表示されます。現代のWebでは事実上の必須要件です。

何を守っているのか

脅威TLSによる防御
盗聴通信内容を暗号化し、途中で覗かれても読めない
改ざん内容が書き換えられたら検知できる
なりすましサーバー証明書で「本物のサイト」であることを証明

接続が始まるまでに起きていること

https:// のページを開くと、画面が出るより前に短いやり取りが済んでいます。これを TLSハンドシェイク と呼びます。

  1. TCPで接続する([[TCP/IP]] の3ウェイハンドシェイク)
  2. サーバーがサーバー証明書を提示する
  3. ブラウザが証明書を検証する — 信頼できる認証局までたどれるか、アクセスしたドメイン名と一致するか、有効期間内か
  4. 双方が計算をやり取りして、この接続でだけ使う共通鍵を作る
  5. 以降のHTTPのやり取りを、その共通鍵で暗号化する

要は4番目です。共通鍵そのものは回線に流れず、双方が手元の計算で同じ鍵にたどり着きます。だから全パケットを記録されていても、後から中身を復号することはできません。現行の TLS 1.3 ではこのハンドシェイクの往復が1回に減り、「HTTPSにすると遅くなる」という心配はほぼ過去のものになりました。

暗号化されないもの

HTTPSにしても隠れないものがあります。暗号化されるのはHTTPの中身 — URLのパス、ヘッダー、Cookie、ボディ — であって、接続先のIPアドレスとホスト名は経路上の機器から見えます。通信の量やタイミングも隠せません。実際に [[パケットキャプチャ]] で覗くと、「誰がいつどのサイトへ接続したか」までは分かるのに中身だけ読めない、という状態が観察できます。「HTTPSなら何を見ていたかまで秘密になる」は誤解です。

初学者向けポイント

  • サーバー証明書 = 認証局(CA)が発行する「このドメインの持ち主は本物」という証明書。Let's Encrypt で無料取得できる
  • 鍵交換には公開鍵暗号、通信本体には高速な共通鍵暗号、とハイブリッドで使い分けている
  • パスワードや [[認証と認可]] のトークンを送る通信は、HTTPSでなければ危険にさらされる

開発者が気をつけること

  • ローカル開発以外は常にHTTPS。フォームやAPIも例外なし(初回アクセスが平文で飛ぶ穴は [[セキュリティヘッダー(CSP・HSTS)]] のHSTSで塞ぐ)
  • 証明書の有効期限切れは定番の障害。自動更新を仕組み化する
  • 「httpsだから安全なサイト」ではない。通信路が安全なだけで、サイト自体の信頼性は別問題

つまずきやすい失敗

  • 混在コンテンツ — HTTPSのページから http:// のスクリプトやCSSを読み込むと、ブラウザがその読み込みをブロックします(画像などはHTTPSへ読み替えられるか警告扱いになります)。「HTTPSにした途端に画面が崩れた」の定番原因です。移行時は埋め込みタグやコードに直書きされたURLまで洗い出します
  • リダイレクトループ — プロキシでTLSを終端し、内部は平文でアプリに渡す構成では、アプリから見た通信は「HTTP」です。ここでアプリが「HTTPだからHTTPSへリダイレクトしよう」と判断すると、永遠に往復し続けます。プロキシが付ける X-Forwarded-Proto ヘッダーを見て判定するよう設定します
  • 期限切れ — 無料証明書の代表である Let's Encrypt は有効期間が90日と短く、手動更新の運用はいずれ必ず破綻します。自動更新と期限監視をセットで組みます
  • 時計のずれ — 証明書の有効期間は時刻で判定されるため、サーバーの時計が大きく狂うと正しい証明書でも「期限切れ」と判定されます([[NTPと時刻同期]])

HTTPSの次に読む地図

HTTPSはWebのほぼ全域に触れるため、隣接する話題が広く散らばっています。目的別に4つの入口を用意しました。

仕組みをもう一段掘る — 「なぜ盗聴されないのか」を理解したいなら、[[暗号化の基礎]] で共通鍵・公開鍵・ハッシュの役割分担を押さえ、[[電子署名とハッシュ]] で改ざん検知と本人性の証明を見て、[[電子証明書とPKI]] で証明書チェーンと認証局へ進むのが最短です。この3本は、上のハンドシェイクの手順にそのまま対応しています。

自分のサイトをHTTPSにする — 証明書を置く場所は、多くの場合アプリ本体ではありません。[[リバースプロキシ]] や [[Nginx]] でTLSを終端して内部は平文にする構成が定番で、静的ファイルが主役なら [[CDN]] のエッジで終端する形もあります。公開そのものの手順は [[ホスティングとレンタルサーバー]] にまとまっています。なお中継者はサーバー側だけでなく利用者側にも立ちます — 会社支給のPCに独自の証明書が入っているのは、[[プロキシサーバー]] が通信内容を検査しているためです。

HTTPSだけでは足りない防御を足す — 通信路が安全でも、アプリ自身の穴は塞げません。最初の1回の平文アクセスを消すHSTSは [[セキュリティヘッダー(CSP・HSTS)]] に、XSSやCSRFといったアプリ側の脆弱性は [[Webセキュリティ]] にあります。ログイン周りでトークンを扱うなら [[OAuth・OIDC]] も併せて読むと、仕様のあちこちに「HTTPS必須」と書かれている理由が腹落ちします。

同じTLSが働いている別の場所 — TLSはWeb専用の技術ではありません。[[HTTP/2とHTTP/3]] のQUICには暗号化が最初から組み込まれ、[[VPN]] のSSL-VPNは同じTLSでトンネルを張り、[[メールの仕組み(SMTP・POP3・IMAP)]] のSTARTTLSも同じ技術です。ブラウザ側では [[PWA]] がHTTPS配信を動作条件にしています。

関連技術とのつながり

  • [[HTTP]] — 暗号化される対象のプロトコル
  • [[TCP/IP]] — TLSはTCPとHTTPの間の層で動く
  • [[認証と認可]] — トークンやCookieを安全に運ぶ前提がHTTPS
Q: TLSハンドシェイクで作られる「この接続でだけ使う共通鍵」について、本文の説明として正しいのはどれ?
- [x] 共通鍵そのものは回線に流れず、双方が手元の計算で同じ鍵にたどり着く
- [ ] サーバーが生成した共通鍵をそのまま平文で送り、ブラウザが受け取る
- [ ] 認証局が接続ごとに共通鍵を発行してブラウザへ配布する
解説: 鍵自体が流れないため、通信をすべて記録されていても後から復号できません。公開鍵暗号は鍵交換に、共通鍵暗号は通信本体に使われます。

Q: HTTPSで通信していても経路上の機器から見えてしまうものはどれ?
- [ ] リクエストのボディに入れた入力内容
- [ ] Cookieに保存されたセッションID
- [x] 接続先のIPアドレスとホスト名
解説: 暗号化されるのはHTTPの中身です。宛先や通信量・タイミングといったメタ情報は隠せません。

Q: プロキシでTLSを終端し内部は平文でアプリへ渡す構成で、リダイレクトループが起きる原因はどれ?
- [ ] 証明書の有効期間が90日と短いため
- [x] アプリが自分に届いた平文のHTTPだけを見て、HTTPSへリダイレクトし続けるため
- [ ] 混在コンテンツをブラウザがブロックするため
解説: プロキシが付ける `X-Forwarded-Proto` ヘッダーを見て判定するよう設定すれば解消します。