HSTS(HTTP Strict Transport Security)
概要
HSTS(HTTP Strict Transport Security) は、ウェブサーバーがブラウザーに対して「このドメインには今後 HTTPS でのみアクセスせよ」と指示するセキュリティポリシーです。RFC 6797(2012 年)で定義されており、Strict-Transport-Security レスポンスヘッダーによって伝達されます。
HTTPS を実装していても、ユーザーが http://example.com と入力した場合や、HTTP のリンクをクリックした場合には最初の接続が HTTP になります。この最初の HTTP リクエストが中間者攻撃(MITM)の窓口になります。攻撃者はこの最初のやり取りを傍受し、HTTPS へのリダイレクトを妨害して HTTP セッションをそのまま維持できます。これが SSL ストリッピング攻撃です。
HSTS はこの問題を解決します。一度 HSTS ヘッダーを受け取ったブラウザーは、指定された期間中、そのドメインへの HTTP リクエストをブラウザー内部で HTTPS に書き換えます。サーバーへの HTTP リクエストは一切送信されません。
仕組み
HSTS は Strict-Transport-Security レスポンスヘッダーでポリシーをブラウザーに伝達し、指定期間中の HTTP アクセスをブラウザー内部で HTTPS に書き換えます。
Strict-Transport-Security ヘッダー
HSTS は HTTPS レスポンスの Strict-Transport-Security ヘッダーで設定します。
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
各ディレクティブの意味は次のとおりです。
max-age は HSTS ポリシーをブラウザーがキャッシュする秒数です。上記の例では 31536000 秒(365 日) です。ブラウザーはこの期間中、HTTP アクセスを HTTPS に自動変換します。ポリシーを解除したい場合は max-age=0 を返すことで削除できますが、削除自体も HTTPS 経由で行う必要があります。
includeSubDomains を指定すると、ポリシーがすべてのサブドメインに適用されます。sub.example.com や api.example.com への HTTP アクセスも自動的に HTTPS へ変換されます。ただし、サブドメインに HTTPS が設定されていない場合、そのサブドメインへのアクセスが完全に失敗します。全サブドメインの HTTPS 対応を確認してから有効にします。
preload ディレクティブは、ドメインをブラウザー組み込みの HSTS preload リストに登録することへの同意を示します。詳細は後述します。
ブラウザーの処理フロー
HSTS が有効な状態でユーザーが http://example.com にアクセスしようとすると、ブラウザーは次の順序で処理します。
- ブラウザーのローカルストアを検索し、
example.comの HSTS エントリーが存在するか確認する - エントリーが存在し、かつ
max-ageが失効していなければ、HTTP リクエストを送信せずに内部的にhttps://example.comへ書き換える - HTTPS でサーバーに接続する
この書き換えはネットワーク通信が発生する前に行われます。したがって、HTTP パケットが実際にネットワーク上を流れることはありません。
HSTS preload リスト
HSTS ヘッダーには「鶏と卵」の問題があります。ブラウザーが初めてそのドメインに訪問するとき、まだ HSTS ポリシーを受け取っていないため、最初のアクセスは HTTP になる可能性があります。
この問題を解消するのが HSTS preload リストです。hstspreload.org で管理されているこのリストは Chrome、Firefox、Safari、Edge などの主要ブラウザーに組み込まれています。リストに登録されたドメインは、一度もアクセスしたことがなくても最初から HTTPS が強制されます。
リスト登録には次の要件を満たす必要があります。
- HTTPS が有効であること
- HTTP から HTTPS への 301 リダイレクトが設定されていること
Strict-Transport-Securityヘッダーにmax-ageが 31536000 以上、includeSubDomains、preloadの 3 つが含まれていること
登録申請は hstspreload.org から行います。承認後、各ブラウザーのリリースに含まれるまで数ヶ月かかる場合があります。また、登録解除にも時間がかかるため、全サブドメインが HTTPS に対応していることを確認してから申請します。
設定例
Nginx や Apache の HTTPS バーチャルホストに Strict-Transport-Security ヘッダーを追加し、HTTP からのリダイレクトを併設します。
Nginx
server {
listen 443 ssl;
server_name example.com;
# HSTS: 1年間、サブドメイン含む
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
}
# HTTP を HTTPS にリダイレクト
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
always パラメーターを付けることで、エラーレスポンス(4xx、5xx)にもヘッダーが付与されます。これがないと、エラーページでは HSTS が有効にならないケースがあります。
Apache
<VirtualHost *:443>
ServerName example.com
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
</VirtualHost>
Apache では mod_headers モジュールが必要です。
確認方法
curl でレスポンスヘッダーを確認するには次のコマンドを使います。
curl -I https://example.com
HTTP/2 200
strict-transport-security: max-age=31536000; includeSubDomains; preload
外部の視点からも確認したい場合は、Labee Dev Toolbox の SSL Cert API を使うと、外部の視点から見た結果を取得できます。
curl "https://labee.dev/api/ssl-cert?hostname=example.com"
{
"success": true,
"data": {
"hostname": "example.com",
"port": 443,
"reachable": true,
"status": 200
},
"error": null,
"meta": { "responseTime": 123 }
}
data.reachable が true であれば HTTPS 接続が成立しています。HSTS は HTTPS が前提のため、この確認は最低限のチェックとして有効です。
よくある問題
HSTS の設定ミスは、サブドメインの HTTPS 未対応や HTTP レスポンスへの誤設定、preload 登録後の解除困難に起因します。
サブドメインの HTTPS 未対応で全滅
includeSubDomains を有効にした後、HTTPS が設定されていないサブドメインへのアクセスが完全に失敗します。legacy.example.com や dev.example.com が HTTP のみの場合、ブラウザーが HTTPS への接続を強制するためアクセス不能になります。includeSubDomains を追加する前に、全サブドメインの HTTPS 対応を DNS とサーバー設定の両面から確認します。
max-age を短くして様子見
HSTS の効果を試したい場合、最初は max-age=300(5分)など短い値で設定して問題がないことを確認してから延ばすアプローチが安全です。preload リスト申請は max-age が 31536000 以上でないと受け付けられませんが、動作検証中は短い値で進められます。
HTTP でのレスポンスに HSTS ヘッダーを設定
Strict-Transport-Security ヘッダーは HTTPS レスポンスに対してのみ有効です。HTTP のレスポンスに設定してもブラウザーは無視します。
preload 登録後の解除に時間がかかる
preload リストからの削除申請後、各ブラウザーのリリースサイクルに依存するため削除が反映されるまで数ヶ月かかります。全サブドメインの HTTPS 対応が不確かな状態で preload 申請すると、解除までの間アクセス不能なサブドメインが残り続けます。
リダイレクトチェーンでの HSTS ヘッダー欠落
http://example.com → https://www.example.com のように、最終的な HTTPS URL と中間の URL が異なる場合、中間リダイレクトのレスポンスにも HSTS ヘッダーが必要です。ヘッダーが最終レスポンスにしか付いていないと、preload リスト要件を満たせません。