0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

HSTSがHTTPSを必須にする仕組みと、配信経路を切り替えるときの制約

0
Posted at

WebサイトをHTTPSで配信するとき、HTTPへのアクセスをHTTPSへリダイレクトすれば足りるように見えます。たとえば、訪問者が次のURLへアクセスしたとします。

http://example.com

サーバーがHTTPSへリダイレクトすれば、最終的には暗号化された通信になります。

http://example.com
    ↓
301 Redirect
    ↓
https://example.com

しかし、この方法には1つ問題が残ります。最初の http://example.com への通信は、まだ暗号化されていません。 この通信を途中で書き換えられると、HTTPSへのリダイレクトそのものを妨害されます。

この問題を塞ぐための仕組みが、HSTSです。

最初の1回を狙う攻撃

訪問者がブラウザーのアドレス欄に example.com と打つとき、https:// を付ける人はほとんどいません。ブックマークや他サイトからのリンクにも、古い http:// が残っています。同じネットワークにいる第三者は、この最初のリクエストを書き換えられます。

訪問者 → http://example.com/          暗号化なし
攻撃者がこの応答を差し替える
攻撃者 → 訪問者                        301 を返さず、HTTP のまま偽のページを返す
訪問者                                 暗号化されていないことに気づかないまま操作を続ける

リダイレクトを返す側がどれだけ正しく設定していても、その応答が訪問者に届かなければ意味がありません。 暗号化されていない1往復が残っている限り、この隙は塞げません。

この手口は SSL stripping と呼ばれます。HTTPSへの切り替えを剥がして、HTTPのまま通信させる攻撃です。

HSTSの宣言

HSTSは HTTP Strict Transport Security の略で、RFC 6797が定義しています。Webサイトがブラウザーに対して「このドメインには、今後HTTPではなく必ずHTTPSで接続してください」と伝える仕組みです。

サーバーはHTTPSの応答に、次のヘッダーを付けます。

Strict-Transport-Security: max-age=31536000; includeSubDomains

max-age の意味は6.1.1節にあります。

The REQUIRED "max-age" directive specifies the number of seconds, after the reception of the STS header field, during which the UA regards the host (from whom the message was received) as a Known HSTS Host.

必須の "max-age" ディレクティブは、STSヘッダーフィールドを受け取ってから、ユーザーエージェントがそのホスト (そのメッセージの送信元) を Known HSTS Host とみなす秒数を指定する。

31536000 は1年ぶんの秒数です。一度このヘッダーを受け取ったブラウザーは、その期間中そのドメインをHSTSの対象として扱います。

includeSubDomains6.1.2節で定義される任意の指定です。

The OPTIONAL "includeSubDomains" directive is a valueless directive which, if present (i.e., it is "asserted"), signals the UA that the HSTS Policy applies to this HSTS Host as well as any subdomains of the host's domain name.

任意指定の "includeSubDomains" ディレクティブは値を持たないディレクティブであり、存在する場合 (すなわち「表明されている」場合)、そのHSTSポリシーがこのHSTSホストだけでなく、そのホストのドメイン名のすべてのサブドメインにも適用されることをユーザーエージェントへ伝える。

この指定を付けると、影響がそのドメインの下のすべてのサブドメインへ及びます。 後述する制約も、同じ範囲へ広がります。

単なるリダイレクトとの違い

HSTSを理解するときに重要なのは、HTTPをHTTPSへ転送する仕組みではないという点です。通常のリダイレクトでは、最初のHTTP通信が発生します。

ブラウザー
    ↓ HTTP          ← ここが暗号化されていない
Webサーバー
    ↓ 301
ブラウザー
    ↓ HTTPS
Webサーバー

HSTSが有効なら、こうなります。

ブラウザー
    ↓ HTTPS
Webサーバー

訪問者が http://example.com と入力しても、ブラウザーはHTTPリクエストを送信しません。ネットワークへ出る前に、内部でHTTPSへ書き換えます。 RFC 6797の要件定義も、UAがHTTPのURIロードをHTTPSへ書き換える必要があると定めています。

つまりHSTSは、HTTPからHTTPSへの切り替えをサーバーのリダイレクトに任せるのではなく、ブラウザー側でHTTP通信そのものを発生させないようにする仕組みです。書き換えの対象そのものが無くなります。

記憶する前の1回目

ここまでの説明には、まだ穴が残ります。ヘッダーを受け取るには、一度HTTPSで接続する必要があります。 そのドメインへ初めてアクセスする訪問者は、まだHSTSを知りません。

1回目   http:// でアクセス   ← まだ守られていない
        HTTPS へリダイレクト
        Strict-Transport-Security を受け取る
2回目    以後は HTTPS のみ    ← 守られる

これを埋めるのが HSTS preload リストです。ブラウザーの開発元が、HSTSを設定しているドメインの一覧をブラウザー本体へ組み込んで配布します。訪問者が一度もアクセスしたことがないサイトでも、最初からHTTPSが強制されます。

登録は hstspreload.org から申請します。後述するとおり、解除の手続きは登録より重くなります。

TLSエラー時に接続を継続できない性質

HSTSには、もう1つ重要な性質があります。HTTPSで問題が起きても、HTTPへ戻れません。

たとえばブラウザーが https://example.com へアクセスし、サーバーの証明書に問題があったとします。通常のサイトなら警告画面が出て、訪問者は「続行」を選べます。

HSTSの対象では、それができません。8.4節がこう定めています。

the UA MUST terminate the connection (see also Section 12 ("User Agent Implementation Advice")) if there are any errors, whether "warning" or "fatal" or any other error level, with the underlying secure transport

ユーザーエージェントは、下位のセキュアなトランスポートに "warning" であれ "fatal" であれ他のいかなるエラーレベルであれ、何らかのエラーがある場合には接続を終了しなければならない (12節「ユーザーエージェント実装の助言」も参照)。

12.1節はさらに踏み込み、危険性を承知で続行する選択肢を出さないよう求めています。ただし12節は、RFC自身が This section is non-normative. と明記する助言の節です。 8.4節のMUSTとは規範の強さが違います。とはいえ、接続を終了させること自体は8.4節のMUSTで既に確定しており、12節が非規範であることはその結果を変えません。

HSTS が無い場合
  証明書のエラー → 警告画面 → 「続行」を押せば見える

HSTS がある場合
  証明書のエラー → 接続終了 → 訪問者にできることが無い

したがってHSTSは、「できればHTTPSを使う」仕組みではありません。HTTPSが正常に使えることを、そのドメインの前提条件にする仕組みです。

解除に必要な条件

HSTSが扱いにくいのは、サーバーからヘッダーを削除しただけでは解除されない点です。ブラウザーは以前受け取った指示をローカルに記憶しています。

解除の方法は仕様に用意されています。6.1.1節の注記です。

A max-age value of zero (i.e., "max-age=0") signals the UA to cease regarding the host as a Known HSTS Host, including the includeSubDomains directive (if asserted for that HSTS Host).

max-age の値がゼロ (つまり "max-age=0") である場合、ユーザーエージェントに対して、そのホストを Known HSTS Host とみなすのをやめるよう伝える。これには、そのHSTSホストに対して指定されている includeSubDomains ディレクティブも含まれる。

ここに循環があります。 max-age=0 を届けるにはHTTPSで正常に接続できなければならず、HTTPSが壊れているときに限ってそれができません。

HTTPS が壊れている
    ↓
ブラウザーは HTTPS でしか接続しない
    ↓
max-age=0 を送れない
    ↓
ポリシーが解除されない

preloadリストへ登録している場合、解除の制約はさらに強くなります。ポリシーがブラウザー本体に組み込まれて配布されるため、解除の手続きを経てブラウザーの更新が行き渡るまで、こちらの都合では動かせません。

配信経路を切り替える場面

ここまでの性質が表面化するのは、そのドメインの向き先を別のサーバーへ変えるときです。CDNを入れる、リバースプロキシを前段に置く、SaaSを配信経路へ挟む。いずれの場合も、DNSの向き先を変える作業が発生します。

切り替え前
  訪問者 → example.com → 元のWebサーバー

切り替え後
  訪問者 → example.com → 新しい入口 → 元のWebサーバー

example.com がHSTSを配信していた場合、訪問者のブラウザーはこのドメインへ必ずHTTPSで接続します。したがって新しい入口は、切り替わった瞬間から https://example.com に対して正常なTLS通信を提供できなければなりません。

DNSだけ先に変更して証明書の準備が終わっていないと、次の状態になります。

DNS を新しい入口へ変更
    ↓
訪問者 → https://example.com
    ↓
新しい入口には example.com 用の証明書が無い
    ↓
TLS エラー
    ↓
接続失敗。訪問者に回避手段が無い

「証明書が出るまで一時的にHTTPで返す」という回避策は使えません。HSTSを記憶しているブラウザーは、そもそもHTTPで接続しないためです。

DNSを元へ戻しても即座には復旧しません。DNSの応答はTTL (Time To Live。応答をキャッシュしてよい秒数) の間キャッシュされ、その値を決めているのは切り替えたゾーンの側です。

順序を決める証明書の取得方式

証明書をどう取得するかが、ここから先の切り替え手順を左右します。証明書の自動発行には ACME という手順が使われ、Let's Encrypt などが対応しています。

発行の前に、認証局は「本当にそのドメインを扱える立場にあるか」を確認します。確認方法は2つあります。

HTTP-01 検証は、http://<ドメイン>/.well-known/acme-challenge/<token> へ実際にアクセスして、指定した内容が返るかを見ます。つまり、そのドメインへのアクセスが新しい入口に届く状態でなければ通りません。

DNS-01 検証は、そのドメインのゾーンに _acme-challenge という名前のTXTレコードを置かせて、その値を見ます。委譲用のCNAMEを1本置いてもらえば、以後の値の更新は入口側のDNSで完結します。確認先が配信経路と無関係です。

この違いが、切り替えの順序を決めます。

HTTP-01では、検証のリクエストが新しい入口へ届く必要があります。単純にDNSを先に切り替えると、証明書が出るまでの間、ドメインは証明書の無い入口を指します。 HSTSが無ければ警告で済む時間帯ですが、HSTSがあると訪問者側に回避手段のない停止になります。

ただしHTTP-01でも順序を入れ替える手はあります。 仕様は検証サーバーがリダイレクトを追うことを認めています。

The server SHOULD follow redirects when dereferencing the URL. Clients might use redirects, for example, so that the response can be provided by a centralized certificate management server.

サーバーはURLを参照する際、リダイレクトに従うべきである。クライアントがリダイレクトを使うのは、たとえば集約された証明書管理サーバーが応答を返せるようにするためである。

現在のサーバーで /.well-known/acme-challenge/ への要求を新しい入口へリダイレクトすれば、DNSを切り替える前にHTTP-01を通せます。 ただしこれは、現在のサーバーに設定を追加してもらう作業が増えることを意味します。

DNS-01なら、DNSを切り替える前に証明書を発行できます。順序を逆にできることが、この方式を選ぶ理由です。

つまり検証方式の選択は、更新の手軽さの問題ではありません。切り替えの失敗から戻れるかどうかを決める、設計上の選択です。

切り替える前に確認する項目

対象のドメインにHSTSが設定されているかは、1回のリクエストで分かります。

curl -sI https://example.com/ | grep -i strict-transport-security

確認するのは3点です。

max-age の値           0 より大きければ、切り戻しが効かない前提で扱う
includeSubDomains      あれば、サブドメイン1つの切り替えでも同じ制約がかかる
preload リストの登録    あれば、解除がブラウザーの更新を待つことになる

preloadリストへの登録状況は hstspreload.org でドメインを検索すれば確認できます。apexで includeSubDomains を設定している場合、その下のサブドメインを1つ切り替えるだけでも同じ制約がかかります。 そのサブドメインがHSTSヘッダーを一度も送ったことが無くても、上位の指定が及んでいます。サブドメイン単体の作業でも、apex側を確認しておく必要があります。

まとめ

HSTSは、HTTPSへのリダイレクトでは塞げない最初の1往復を、ブラウザー側でHTTP通信を発生させないことによって塞ぐ仕組みです。

宣言       Strict-Transport-Security ヘッダーを HTTPS の応答で返す
効果       ブラウザーが HTTP でリクエストを送らなくなる
副作用     TLS エラーが警告ではなく接続終了になる
解除       max-age=0 を送る必要があるが、送るには HTTPS 接続が要る
preload    ブラウザー本体に組み込まれ、解除がさらに遅れる

HSTSは「HTTPSを推奨する設定」ではなく、「HTTPSが常に正常に動くことを前提にする」という宣言です。 この違いは、平常時には現れません。配信経路を切り替えるときに初めて現れます。

そのため、HSTSを設定しているドメインの配信経路を変えるときは、DNSの向き先だけを見るのでは足りません。証明書がいつ用意できるか、失敗したときに訪問者がアクセスできる状態へ戻せるかまでを、1つの手順として設計する必要があります。

参考情報

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?