HSTS Preload設定手順|nginx・Cloudflare実装とhstspreload.org申請ガイド
- HSTS Preloadは、ブラウザに組み込まれた静的リストにより初回訪問からHTTPSを強制する仕組みだ。
- 実装の核心は
Strict-Transport-Security: max-age=31536000; includeSubDomains; preloadをHTTPSレスポンスだけに返すこと、そして includeSubDomains 配下の全サブドメインがHTTPS対応済みであること。 - 登録はほぼ不可逆なので、hstspreload.org への申請は段階的導入と棚卸しを終えてから行う。
HSTS(HTTP Strict Transport Security)とは
HTTPSサイトでも、ユーザーがアドレスバーに http:// と入力したり、公共Wi-Fi上で攻撃者が接続をHTTPへダウングレードしたりすると、最初の1リクエストだけ平文で流れる隙間がある。攻撃者はこの瞬間にSSLストリッピング(HTTPSを装わずHTTPのまま中継する攻撃)を仕掛けられる。
HSTSはサーバーが返す Strict-Transport-Security レスポンスヘッダーで、ブラウザに「このホストには max-age 秒間、HTTPではなくHTTPSで接続せよ」と指示する仕組みだ。一度HTTPSでアクセスしたブラウザは、以降 http://example.com を入力しても、ネットワークにHTTPリクエストを送る前に内部で https://example.com に書き換える。
代表的なヘッダー:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
| ディレクティブ | 意味 |
|---|---|
max-age | HSTSポリシーの有効期間(秒)。Preload要件は 31536000(1年)以上 |
includeSubDomains | *.example.com 配下のサブドメインにも適用。Preload申請では必須 |
preload | 運営者がPreloadリストへの登録を意図していることを示す。申請手続きは別途必要 |
通常のHSTSだけでは「まだHSTSを知らないブラウザの初回訪問」はHTTPのまま到達しうる。Preloadはこの穴を塞ぐが、副作用も大きい。
Preloadリストが解決する「初回アクセス問題」
HSTS Preload は、Chrome・Chromium系・Firefox・Safari・Edgeなど主要ブラウザに静的に組み込まれたドメインリストだ。リストに載った example.com へは、ユーザーが一度も訪問したことがなくても、ブラウザは最初からHTTPSのみで接続する。
リストの運用窓口は hstspreload.org。要件を満たしたドメインを申請すると、審査のうえ各ブラウザベンダーへ配布され、次期ブラウザリリースに反映される。反映まで数週間〜数ヶ月かかることもある。
| 観点 | 通常HSTS / Preload |
|---|---|
| 適用タイミング | 通常: 初回HTTPS訪問後 / Preload: 初回から |
| 必要なヘッダー | 通常: max-age のみ可 / Preload: preload + includeSubDomains + max-age≥1年 |
| サブドメイン | Preloadは includeSubDomains 必須。未対応サブドメインがあると申請不可または運用事故 |
| 取り消し | 通常: max-age切れで自然消滅 / Preload: リスト更新まで数ヶ月〜数年 |
| 主な防御 | 両方: SSLストリッピング・プロトコルダウングレード攻撃の抑制 |
Preload登録の公式要件(hstspreload.org)
hstspreload.org が定める申請要件は次のとおり。サイト上の自動チェッカーがこれらを検証する。
- apexドメイン(
example.com)がHTTPSで応答する - wwwサブドメイン(
www.example.com)がHTTPSで応答する(wwwなしのみのサイトでも、wwwへのリダイレクトまたは同等のHTTPS応答が必要) - HTTP(平文)アクセスは恒久的な301リダイレクトでHTTPSへ誘導する(302・307・メタリフレッシュ・JavaScriptリダイレクトは不可)
- HTTPSレスポンスに
Strict-Transport-Securityヘッダーがあり、max-ageが 31536000 以上 - ヘッダーに
includeSubDomainsが含まれる - ヘッダーに
preloadディレクティブが含まれる - すべてのサブドメインがHTTPS対応であること(includeSubDomains の意味上の前提)
申請前の確認コマンド:
# HTTPSでHSTSヘッダーを確認(preload を含むこと)
curl -sI https://example.com | grep -i strict-transport-security
# HTTPが301でHTTPSへ飛ぶこと
curl -sI http://example.com | grep -iE "^(HTTP/|location:)"
# www側も同様に確認
curl -sI https://www.example.com | grep -i strict-transport-security
curl -sI http://www.example.com | grep -iE "^(HTTP/|location:)"
期待される出力例:
strict-transport-security: max-age=31536000; includeSubDomains; preload
HTTP/1.1 301 Moved Permanently
location: https://example.com/
nginxでのHSTS実装(本番設定例)
nginxでは HTTPS(443)の server ブロックだけ にHSTSを付与する。always フラグを付けないと、4xx/5xxレスポンスでヘッダーが落ちる場合があるため、Preload申請前は always を推奨する。
# HTTP → HTTPS 恒久リダイレクト(80番)
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
# HSTSヘッダーはここには付けない
return 301 https://$host$request_uri;
}
# HTTPS(443番)— HSTSはここだけ
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Preload申請用の完全形
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
root /var/www/example.com;
index index.html;
}
サブドメインごとに server ブロックを分ける場合、includeSubDomains を宣言している以上、リストアップした全ホストでHTTPSが有効である必要がある。api.example.com だけ別サーバーでHTTPのまま、という状態はPreload申請前に解消する。
段階導入時は max-age を短く始める:
# 検証フェーズ(5分)。問題なければ 86400 → 31536000 へ延長
add_header Strict-Transport-Security "max-age=300" always;
設定反映後は nginx -t && systemctl reload nginx で構文チェックとリロードを行う。
CloudflareでのHSTS設定と注意点
Cloudflare経由のサイトは、ダッシュボード SSL/TLS → Edge Certificates → HTTP Strict Transport Security (HSTS) からEdgeレスポンスにHSTSを付与できる。
| 設定項目 | Preload申請時の推奨値 |
|---|---|
| Enable HSTS | ON |
| Max Age | 12 months(31536000秒)以上 |
| Include subdomains | ON(必須) |
| Preload | ON(必須) |
| No-Sniff header | 任意(X-Content-Type-Options と併用推奨) |
Cloudflare有効時、ブラウザが受け取るレスポンス例:
strict-transport-security: max-age=31536000; includeSubDomains; preload
注意すべき点:
- Always Use HTTPS(SSL/TLS → Edge Certificates)をONにし、HTTPリクエストがEdgeで301リダイレクトされることを確認する
- Cloudflareとオリジンnginxの両方でHSTSを返すと、値が異なる場合にどちらが有効か分かりにくい。Edgeかオリジンのどちらか一方に集約する
- Flexible SSL(Cloudflare↔ブラウザはHTTPS、Cloudflare↔オリジンはHTTP)はHSTSと相性が悪い。Full(Strict)を推奨
- オレンジクラウド(プロキシ)がOFFのサブドメインはCloudflareのHSTSが効かない。includeSubDomains 下でHTTPが残ると申請要件を満たせない
Cloudflare Transform Rulesで手動付与する場合(ダッシュボード設定の代替):
# Response Header の Set 操作
Strict-Transport-Security = max-age=31536000; includeSubDomains; preload
includeSubDomainsのリスクとサブドメイン棚卸し
includeSubDomains は example.com だけでなく anything.example.com すべてにHSTSを及ぼす。Preload申請では省略できないため、申請前にサブドメインの完全な棚卸しが必須だ。
典型的な事故パターン:
| サブドメイン | 想定外の影響 |
|---|---|
staging.example.com | 開発環境がHTTPのままだと、Preload後に開発者がアクセス不能になる |
mail.example.com | レガシーメールサーバーがHTTP管理画面のままだと到達不能 |
old-api.example.com | 証明書期限切れのサブドメインは、ブラウザが接続を拒否し続ける |
dev.example.com | 社内のみのHTTPサービスが外部からもHTTPS強制される |
棚卸し手順:
DNSゾーンの全レコード(A/AAAA/CNAME)をエクスポートし、*.example.com のホスト名をリスト化する
各ホストに対し curl -sI https://<host>/ で証明書エラーがないか確認する
HTTPのみのホストは301でHTTPSへリダイレクトするか、サービスを廃止・別ドメインへ移す
使わないサブドメインのDNSレコードを削除し、第三者が取得できないようにする
includeSubDomains 付きの短い max-age で1週間様子を見てから preload を付与する
includeSubDomains は example.com のサブドメインにのみ 効く。example-staging.com のような別ドメインは対象外だ。検証環境はサブドメインではなく別ドメインに置くのが安全な設計パターンだ。
リダイレクトループの原因とデバッグ手順
HSTS導入時に最も混乱しやすいのがリダイレクトループだ。ブラウザが「HTTPSで接続しろ」と記憶しているのに、サーバー側がHTTPへ戻そうとしたり、証明書とホスト名が一致しない場合に発生する。
よくある原因:
- HTTPレスポンスにHSTSヘッダーを付けている — 平文接続でもブラウザがHTTPSを強制し、設定ミスと組み合わさってループする
- Flexible SSL + オリジンHTTPリダイレクト — EdgeはHTTPS、オリジンは「HTTPSで来たリクエストをHTTPへ」と誤設定
- 証明書のCN/SAN不一致 —
www.example.comの証明書がなく、HTTPS接続が失敗→リトライの繰り返し - ロードバランサとオリジンの二重リダイレクト — LBがHTTPS終端し、オリジンへHTTP転送、オリジンが再びHTTPSへ301
- HSTS preload 済み + 一時的なHTTP運用への切り戻し — ブラウザがHTTPを拒否するため「戻せない」状態に見える
デバッグ手順:
# 1. リダイレクトチェーンを追跡(ループ検出)
curl -sI -L --max-redirs 10 http://example.com
# 2. HTTPSレスポンスのステータスとHSTSを確認
curl -sI https://example.com
# 3. 証明書のSANを確認
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -ext subjectAltName
ブラウザ側の確認:
- Chrome:
chrome://net-internals/#hsts→ 「Query HSTS/PKP domain」にドメインを入力し、ポリシー有無を確認 - 削除テスト: 同画面の「Delete domain security policies」でローカルのHSTSキャッシュを消し、挙動を再現する(Preloadリスト自体は消えない)
return 301 https://... する HTTPの server ブロックに add_header Strict-Transport-Security を書かない こと。HTTPSブロックだけに書くのが鉄則だ。
ループが疑われるときの切り分け表:
| 症状 | 疑う箇所 |
|---|---|
| curl は正常、ブラウザだけループ | ブラウザのHSTSキャッシュまたはPreloadリスト |
| www のみ失敗 | www用証明書・server_name の不足 |
| Cloudflare経由のみ失敗 | SSLモード(Flexible/Full)とオリジンリダイレクト |
| 全員に突然発生 | 証明書期限切れまたはDNS変更 |
hstspreload.orgへの申請チェックリスト
申請は https://hstspreload.org/ のフォームから行う。以下をすべて満たしてから送信する。
インフラ・証明書
- apex(
example.com)が有効なHTTPS証明書で応答する -
www.example.comが有効なHTTPS証明書で応答する -
http://example.comが301でhttps://へリダイレクトする -
http://www.example.comが301でhttps://へリダイレクトする - 証明書の自動更新(Let’s Encrypt / ACME 等)が稼働している
HSTSヘッダー
-
https://example.comのレスポンスにStrict-Transport-Securityがある -
max-ageが31536000以上 -
includeSubDomainsが含まれる -
preloadが含まれる - HTTP(平文)レスポンスにはHSTSヘッダーがない
サブドメイン
- DNS上の全サブドメインを棚卸し済み
- HTTPのみのサブドメインが残っていない
- 証明書エラーのサブドメインが残っていない
- 不要なワイルドカードDNSが第三者に悪用されない
申請・承認後
- hstspreload.org のドメインチェッカーでエラーなし
- 申請用メールアドレスで確認メールを受信・承認できる
- 社内関係者に「Preload申請済み・取り消し困難」を共有した
- 承認後、数週間〜数ヶ月待って
chrome://net-internals/#hstsで登録を検証した
申請後のステータスは hstspreload.org から配信されるメール、または Chromium の hstspreload master list で確認できる。
Preload登録の取り消しが困難な理由
Preloadは「ブラウザに焼き込まれたHTTPS強制」に近い。通常のHSTSは max-age が切れればブラウザの記憶から消えるが、Preloadリストのドメインはブラウザをアップデートするまでリストに残り続ける。
解除に必要な作業(すべてを満たしても時間がかかる):
- HTTPSレスポンスから
preloadを削除し、includeSubDomainsも外す max-age=0のStrict-Transport-Securityヘッダーを配信し続ける(古いキャッシュの上書き用)- hstspreload.org/removal/ から削除申請を行う
- 各ブラウザベンダーが次期リリースでリストを更新するまで待つ(数ヶ月〜1年以上の事例も報告されている)
- ユーザーのブラウザがそのバージョンに更新されるまで、古いリストが残る
つまり「一時的にHTTPに戻したい」「サブドメインだけHTTPにしたい」という要件が出た時点で、Preload済みドメインは選択肢が極端に少ない。新規ドメインへの移行や、検証環境の完全分離(別 registrable domain)を検討するケースも出る。
いきなりPreload申請せず、(1) 短い max-age でHSTS投入 → (2) サブドメイン棚卸し → (3) max-age を1年へ延長 → (4) preload を付与して1週間観察 → (5) hstspreload.org 申請、の順が安全だ。
段階的導入のベストプラクティス
実務では次のフェーズで進めると、ロールバック余地を保ちながらPreloadまで到達できる。
フェーズ1 — リダイレクトと証明書(Preloadなし)
- HTTP→HTTPSの301をapex/wwwに設定
- 全サブドメインの証明書を確認
- HSTSはまだ付けない、または
max-age=0で挙動確認
フェーズ2 — 短期HSTS(preloadなし)
add_header Strict-Transport-Security "max-age=300" always;
1週間、エラーログ・ユーザー問い合わせ・内部ツールの接続を監視する。
フェーズ3 — 本番HSTS(preloadなし)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
includeSubDomains 付きで1ヶ月運用し、ステージングサブドメイン事故がないか確認する。
フェーズ4 — preload 付与と申請
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
1週間以上問題なければ hstspreload.org へ申請する。
運用面では、証明書の自動更新失敗アラート、HTTPリンクの残存チェック(メールテンプレート・OGP・旧ブックマーク)、CDNとオリジンの設定ドリフト検知をセットにすると、Preload後の事故を防ぎやすい。
関連記事
この記事は セキュリティ テーマの一環です。あわせて読むと理解が深まる関連記事をまとめました。
| トピック | 記事 |
|---|---|
| XSS攻撃と防御の完全ガイド | XSS攻撃と防御の完全ガイド|反射型・蓄積型・DOM型の対策 |
| CSRF対策の実装ガイド | CSRF対策の実装ガイド|SameSite・Synchronizer Token・Laravel/Expressコード |
| Double Submit Cookie完全実装 | Double Submit Cookie完全実装|Synchronizer Token比較・SPA+JWT・サブドメイン攻撃 |
| Content Security Policy (CSP) 設定ガイド | Content Security Policy (CSP) 設定ガイド|XSS・クリックジャッキング対策 |
| CSP Report-Only 段階導入ガイド | CSP Report-Only 段階導入ガイド|本番を壊さずポリシーを検証する |
| セキュリティヘッダー一覧と設定ガイド | セキュリティヘッダー一覧と設定ガイド|CSP・HSTS・Referrer-Policy・Permissions-Policy |
| セキュアなCookie設定ガイド | セキュアなCookie設定ガイド|HttpOnly・Secure・SameSiteの使い分けとCSRF対策 |
| CORSエラーの対処法 | CORSエラーの対処法|「Access-Control-Allow-Origin」で解決する |
| CORSプリフライトリクエスト | CORSプリフライトリクエスト|OPTIONSが飛ぶ条件と正しい応答 |
| ローカル開発でCORSエラーが出る原因と3つの回避策 | ローカル開発でCORSエラーが出る原因と3つの回避策 |
| OAuth2 PKCE SPA実装ガイド | OAuth2 PKCE SPA実装ガイド|Authorization Code + S256 + BFFパターン |
| Passkeys・WebAuthn実装の基礎 | Passkeys・WebAuthn実装の基礎|FIDO2・Resident Key・@simplewebauthn/server |
まとめ
HSTSは「HTTPSで一度訪れたユーザー」を守り、Preloadは「初めて訪れるユーザー」まで守る。nginx では443番の server ブロックに add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; を設定し、80番は301リダイレクトのみ。Cloudflare では Edge Certificates のHSTS設定で同等の値を有効化し、Flexible SSLを避ける。
申請前の必須作業は、全サブドメインのHTTPS化、HTTPの301リダイレクト、curl と hstspreload.org による検証の3点。includeSubDomains は1つでもHTTPや証明書エラーが残ると致命的で、Preload登録後の取り消しは数ヶ月〜数年かかる。段階的導入でリスクを下げ、リスト登録は長期的なコミットメントとして計画してから hstspreload.org で申請しよう。