HSTS(HTTP Strict Transport Security)は、ブラウザに常にHTTPSで接続するよう指示するセキュリティヘッダーです。ユーザーがhttp://と入力したりHTTPリンクをクリックしたりしても、このヘッダーを受け取ったブラウザは、そのドメインへの将来のリクエストをすべて自動的にHTTPSにアップグレードし、ダウングレード攻撃と安全でない接続を防止します。
HSTSが重要な理由
HSTSがないと、サイトへの最初のリクエストがHTTP(301リダイレクトが効く前)になる可能性があります。その短い間に、ネットワーク上の攻撃者は:
- HTTPSをストリップ — リダイレクトを傍受し、ユーザーをHTTPのままにする(SSLストリッピング攻撃)
- Cookieを盗む — 最初のHTTPリクエストでCookieが送信された場合
- コンテンツを注入 — リダイレクトレスポンスを改変
HSTSはこのウィンドウを排除します。最初のHTTPS訪問後、ブラウザは二度とHTTPを試みません。
HSTSを有効にする方法
Nginx
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
HTTPS serverブロック(ポート443)内に追加してください。HTTPリダイレクトブロックには追加しないでください。
Apache
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
mod_headersが必要です(sudo a2enmod headers)。
Cloudflare
Dashboard → SSL/TLS → Edge Certificates → HTTP Strict Transport Security (HSTS) → Enable。
HSTSパラメータ
| パラメータ | 例 | 意味 |
|---|---|---|
max-age | 63072000(2年) | ブラウザがHTTPSを使用することを記憶する期間(秒) |
includeSubDomains | — | HSTSをすべてのサブドメインにも適用 |
preload | — | HSTSプリロードリストへの参加意思を示す |
max-ageの選択
| フェーズ | max-age | 目的 |
|---|---|---|
| テスト | 300(5分) | コミットする前にHTTPSが動作するか確認 |
| 確信あり | 604800(1週間) | ロールバック必要時のリスクが低い |
| 本番 | 31536000(1年) | 標準的な推奨 |
| 長期 | 63072000(2年) | プリロードリストに必要 |
小さく始めて、徐々に増やしてください。 長いmax-ageがキャッシュされている間にHTTPSが壊れると、訪問者はサイトにアクセスできなくなります — ブラウザがHTTP接続を拒否します。
HSTSプリロード
HSTSプリロードリストは、ブラウザにハードコードされたドメインのリストで、最初の訪問からでも(HSTSヘッダーを受け取る前でも)常にHTTPSを使用します。
プリロードの要件
- 有効なHTTPS証明書を配信
- 同じホストでHTTPからHTTPSへリダイレクト
max-age≥ 63072000(2年)のHSTSヘッダーincludeSubDomainsディレクティブを含むpreloadディレクティブを含む
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
プリロードの送信
hstspreload.orgにアクセスし、ドメインを入力して送信します。レビュー後(数週間〜数か月)、ドメインがブラウザの組み込みリストに追加されます。
プリロードに関する注意
- 元に戻すのが困難です。 プリロードリストからの削除には数か月とブラウザのリリースサイクルが必要です。その間、ドメインはHTTPS経由でのみアクセスできます。
includeSubDomainsが必須 — すべてのサブドメインがHTTPSをサポートする必要があります。staging.example.comに証明書がなければ、アクセスできなくなります。- 確信がある場合のみプリロード — 現在と将来のすべてのサブドメインがHTTPSをサポートすること。
よくある間違い
HTTPレスポンスにHSTSを設定する
HSTSはHTTPS経由でのみ送信する必要があります。HTTPリダイレクトもHSTSヘッダーを送信する場合、ブラウザはそれを無視します(仕様ではHTTPSが必要)。ポート443ブロックのみにヘッダーを設定してください。
サブドメインの忘れ
includeSubDomainsはすべてのサブドメインにHSTSを適用します。internal.example.comにHTTPSがなければ、アクセスできなくなります。有効にする前にすべてのサブドメインを監査してください。
max-ageを早い段階で高く設定しすぎる
HTTPSが壊れた場合(証明書の期限切れ、設定エラー)、訪問者はHTTPにフォールバックできません。ブラウザが接続を拒否します。5分から始め、すべてが動作することを確認してから1年に増やしてください。
HSTSがアクティブか確認する方法
curl -sI https://yourdomain.com | grep -i strict-transport
# 期待値: strict-transport-security: max-age=63072000; includeSubDomains
Chrome DevToolsで:Networkタブ → リクエストをクリック → Headers → Strict-Transport-Securityを探す。
よくある質問
HSTSはHTTP→HTTPSリダイレクトを置き換えますか?
いいえ。HSTSとリダイレクトは異なる目的を果たします。リダイレクトは最初のHTTPリクエストをキャッチします。HSTSはブラウザに(最初のHTTPS訪問後)二度とHTTPリクエストをしないよう伝えます。両方が必要です。
HSTSは問題を引き起こしますか?
はい、HTTPSが壊れた場合。長いmax-ageでは、ブラウザがフォールバックとしてHTTP接続を拒否します。このため、短いmax-ageから始め、HTTPSが安定してからのみ増やすべきです。
Cloudflareを使っている場合、HSTSは必要ですか?
Cloudflareは訪問者→Cloudflare接続を処理しますが、オリジンのHSTSは完全なチェーンを保護します。エッジにはCloudflareのダッシュボードからHSTSを有効にし、Full (Strict)モードを使用している場合はオリジンでも有効にしてください。
HSTSとupgrade-insecure-requests CSPディレクティブの違いは何ですか?
upgrade-insecure-requestsは、サブリソース(画像、スクリプト)をHTTPの代わりにHTTPS経由で読み込むようブラウザに指示します — 混合コンテンツの修正です。HSTSは、ドメイン全体に常にHTTPSを使用するようブラウザに指示します。異なる問題を解決し、併用できます。