理系学生日記

おまえはいつまで学生気分なのか

はてなBlogをHTTPS化したので HSTS、upgrade-insecure-requests あたりをまとめる

先日、はてなブログが HTTPS に対応したということで、このブログも HTTPS 化を実施しました。 このエントリを見ているとき、ブラウザのロケーションバーを見ると HTTPS になっていることが確認できると思います。

今日は、この HTTPS 化にからめて、混在コンテンツ、HTTP Strict Transport Security (HSTS) 、upgrade-insecure-requests あたりをまとめてみたいと思います。

HTTPS 化の流れ

そもそも、みなさんご存知のように、最近は全サイトを HTTPS 化しようという流れになっています。

下記のページに依ると、2018/04/14 における「Chrome で HTTPS 経由で読み込まれたページの割合」は、61 % になってたりします。

HTTPS 化への流れはセキュリティが主題ですが、これに伴い、SEO にも関連します。

混在コンテンツ

で、HTTPS 化するにあたって、必ず出てくるのがこの混在コンテンツ(mixed contents) の問題です。

混在コンテンツというのをざっくり言うと、HTTPS で提供されるページから HTTP 経由で読みこまれるリソースです。 こうなると、(Secure じゃない)Cookie の盗聴やら、中間者攻撃やらにさらされるので、基本的には忌むべき存在となります。

この混在コンテンツには、大きく以下の 2 種類に分けられます。

  • Optionally-blockable Content
  • Blockable Content

このあたりは、Mixed Content に定義があります。

Optionally-blockable Content は、HTTPS ページから読み込まれる <img><video><audio> といったリソースで、 各ブラウザは警告は出すものの、リソースを 読み込む という判断をしています。 セキュリティのリスクはあるはあるんですが、そのリスクよりも、「読み込めないと判断したときの影響」の方がでかいよね、って話です。

一方、Blockable Content はそれ以外のリソースで、代表的なのは <script> とかです。 こっちについては、ブラウザはセキュリティリスク高と判断して読み込みをブロックします。

頻繁に見ると思うんですが、以下が Chrome のコンソールに出力されるログですね。上が Optionally-blockable、下が Blockable。

f:id:kiririmode:20180419094536p:plain

HSTS

で出てきたのが HTTP Strict Transport Security (HSTS) です。

HSTS は簡単に言うと、サイトを閲覧するときに、HTTP ではなくぜったいに HTTPS にしようぜっていう仕組みです。 だいたいブラウザとサーバ間の挙動は以下のようになります。

ブラウザが HTTP のページにアクセスした場合

  1. ブラウザが HTTP のページにアクセスする
  2. サーバはステータスコード 301 でリダイレクト

→以下、次のフローに乗る

ブラウザが HTTPS のページにアクセスした場合

  1. ブラウザが HTTPS のページにアクセスする
  2. サーバは Strict-Transport-Security (STS)ヘッダを返す
    • twitter.com は strict-transport-security: max-age: 631138519
    • wikipedia.org は strict-transport-security: max-age=106384710; includeSubDomains; preload
  3. ブラウザは、対象ホストが:
    • まだブラウザ内に HSTS Host として登録されていない場合は、対象ホストを HSTS Host として登録する
    • ブラウザ内に HSTS Host として登録されている場合は、STS ヘッダの内容をブラウザ内に登録する

ミソは 3. で、この後、ブラウザが対象ホストにアクセスする場合は http ではなく意地でも https にアクセスします。 この辺りの挙動は Chrome だと分かりやすくて、以下が http://www.wikipedia.org にアクセスしたときのヘッダなのですが、 307 Internal Redirect で https にリダイレクトするようになっています。このリダイレクト、「Internal Redirect」の Phrase のとおり、Chrome 内部での疑似レスポンスです。

f:id:kiririmode:20180419125010p:plain

Firefox の場合はこの疑似リダイレクトとかは見えません。ロケーションバーに http://www.wikipedia.org と打ち込んでエンターを押しても、勝手に https でアクセスしたことになります。

あれ、少なくとも一度 HTTP にアクセスするならそこを MITM で狙われるのでは

これはそのとおりで、ブラウザが HSTS ホストとして認識していないホストにアクセスするときは、HTTP でアクセスせざるを得ないことが有り得ます。 この対策として、各ブラウザはそのリリース段階で多数のホストを HSTS ホストとして登録しています。上に挙げた twitter.com とか wikipedia.org とかはまさにその例です。 こうやって、一度たりとも HTTP を許さない方法を Preloaded HSTS とか呼んだりします。

この Preloaded HSTS の対象ホストの一覧は、

にあります。Chrome のリストに追加希望がある場合は、たしか HSTS Preload List Submission から申請できるはず。

HSTS ホストとして登録されているかを確認する方法

Preloaded HSTS ホストなら上記の一覧を見れば良いですが、Preloaded でないホストを含めて自分のブラウザを確認したい場合は、chrome://net-internals/#hsts にアクセスすれば良いです。 こんな感じでクエリできます。

f:id:kiririmode:20180419130050p:plain

upgrade-insecure-requests

上述の通り、完全 HTTPS 化できたサイトは HSTS 適用すれば良いんですが、一部 HTTP が残っちゃう、みたいな場合に役立つのが、この upgrade-insecure-requests です。 Content-Security-Policy (CSP) の一種なんですが、upgrade-insecure-requests の目的は、「HTTPS にマイグレーションするときの管理者/開発者の負荷を下げること」にあります。

挙動については、HTTP のレスポンスヘッダに Content-Security-Policy: upgrade-insecure-requests が含まれているページで、以下のような http 経由の画像参照があった場合、

<img src="http://example.com/image.png">
<img src="http://not-example.com/image.png">

ブラウザはあたかも以下のように書いてあるものと解釈して、画像のフェッチを実行します。

<img src="https://example.com/image.png">
<img src="https://not-example.com/image.png">

もちろん、これらの画像が HTTPS で取得できない場合は、http に fallback することなくネットワークエラーとして扱われます。

HSTS と競合するのでは?

上記のように,強制的に http -> https と変更するという意味では、HSTS と同じようにも思えるのですが、W3C 的にも upgrade-insecure-requests だと HTTP 通信が行われることを防げないことを記載しています。

Authors can and should continue to use that header to ensure that their users are not subject to SSL stripping downgrade attacks, as the upgrade-insecure-requests directive will not ensure that users visiting your site via links on third-party sites will be upgraded to HTTPS for the top-level navigation.

Upgrade Insecure Requests

参考資料