.devドメインと.appドメインがHTTPSを強制する仕組み

トップレベルドメインの中に.devと.appがある．これらはHTTPS接続を強制するドメインとして知られている．この仕組みが気になっていたので調べてみた．

参考: [グーグル、完全HTTPS接続で安全なアプリ用ドメイン「.app」--早期登録を受付開始 - CNET Japan](https://japan.cnet.com/article/35118647/)

# 仕組み

結論: **HSTS**の**Preload List**という技術を使っている．

## HSTS

HSTS(HTTP Strict Transport Security)はHTTPでアクセスしてきたユーザ(HTTPクライアント)にHTTPSでのアクセスを強制するための技術である．対応しているWebサイトでは，HTTPレスポンスのヘッダに `Strict-Transport-Security: xxx` が付与されている．Qiitaの場合は`strict-transport-security: max-age=2592000`が設定されている．[RFC 6797](https://tools.ietf.org/html/rfc6797)で定義されている．

参考: [Strict-Transport-Security - HTTP | MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security)

FacebookはHSTS Preloadがレスポンスヘッダに含まれている．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/fa23927e-0c5e-d55d-87db-9af229d9e0a0.png)

## Preload List

Preload Listは[RFC 6797](https://tools.ietf.org/html/rfc6797#section-12.3)の中で定義されている．サイトの管理者は事前に定義したHSTSポリシーをpre-loaded listとよばれるリストにもたせることができる．このリストは，ブラウザがルート認証局の証明書を持つのと同様に，ブラウザに埋め込まれている．これは**Bootstrap MITMの脆弱性**(後述)からの保護に役立つ．

Preload Listに含まれているドメインは，初回にWebブラウザでHTTPアクセスした場合もHTTPSアクセスを強制される．これにより，初回からHTTPSでの通信を行える．

![HSTSの説明.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/0777b67d-0989-f0cc-685d-29703add52fa.png)

FacebookはブラウザからHTTPでアクセスすると，ブラウザの内部でHTTPSへリダイレクトが行われる．Status Codeは**307 Internal Redirect**になる．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103672/c251eacf-f3bf-c609-9dc8-267babf676e9.png)

以下は，MozillaのPreload Listの一部である．5/12の段階でファイル全体は95377行ある．

```shell
$ curl -s https://hg.mozilla.org/mozilla-central/raw-file/tip/security/manager/ssl/nsSTSPreloadList.inc | head -20
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/*****************************************************************************/
/* This is an automatically generated file. If you're not                    */
/* nsSiteSecurityService.cpp, you shouldn't be #including it.                */
/*****************************************************************************/

#include <stdint.h>
const PRTime gPreloadListExpirationTime = INT64_C(1600956010611000);
%%
0--1.de, 1
0-1.party, 1
0-24.com, 1
0-24.net, 1
000321365.com, 1
0007552.com, 1
000a1.com, 1
000a2.com, 1
```

例えば，`facebook` が含まれているドメインの一覧は19件ある．

```shell
$ curl -s https://hg.mozilla.org/mozilla-central/raw-file/tip/security/manager/ssl/nsSTSPreloadList.inc | grep facebook
apps.facebook.com, 0
business.facebook.com, 0
code.facebook.com, 0
connect.facebook.net, 1
developers.facebook.com, 0
facebook-atom.appspot.com, 1
facebook.ax, 1
facebook.com, 0
m.facebook.com, 1
mbasic.facebook.com, 0
mtouch.facebook.com, 0
pixel.facebook.com, 0
research.facebook.com, 0
secure.facebook.com, 0
t.facebook.com, 0
tablet.facebook.com, 0
touch.facebook.com, 0
upload.facebook.com, 0
www.facebook.com, 0
```

ChromiumのPreload Listは5/22の段階で110787行ある．

```shell

$ curl -s https://raw.githubusercontent.com/chromium/chromium/master/net/http/transport_security_state_static.json | tail
    { "name": "briellenj.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
    { "name": "blainecosheriff-ok.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
    { "name": "almaarkansas.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
    // END OF ETLD-OWNER REQUESTED ENTRIES

    // To avoid trailing comma changes from showing up in diffs, we place a
    // single entry at the end.
    { "name": "hstspreload.org", "policy": "custom", "include_subdomains": true, "mode": "force-https" }
  ]
}
```

Facebookを含むドメインは22件ある．よく見ると`facebooktsukaikata`という文字列を含むドメインもある．

```shell
$ curl -s https://raw.githubusercontent.com/chromium/chromium/master/net/http/transport_security_state_static.json | grep 'facebook'
      "name": "facebook",
    // Facebook would like to have pinning enforced on (*.)facebook.com and
      "name": "facebook.com", "policy": "custom",
      "mode": "force-https", "pins": "facebook", "include_subdomains_for_pinning": true
    { "name": "www.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "m.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "tablet.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "secure.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "pixel.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "apps.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "upload.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "developers.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "touch.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "mbasic.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "code.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "t.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "mtouch.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "business.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "research.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
      "mode": "force-https", "pins": "facebook", "include_subdomains_for_pinning": true
    { "name": "www.messenger.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "facebook-atom.appspot.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
    { "name": "facebook.ax", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
    { "name": "facebooktsukaikata.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
    { "name": "connect.facebook.net", "policy": "custom", "mode": "force-https", "include_subdomains": true },
```

.appドメインと.devドメインはトップレベルドメインとして登録されている．

```shell
$ curl -s https://raw.githubusercontent.com/chromium/chromium/master/net/http/transport_security_state_static.json | egrep '("dev"|"app")'
    { "name": "app", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true },
    { "name": "dev", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true },
```

どちらのPreload Listもソースコードと同封されていた．つまり，ユーザはビルド済みWebブラウザに内包されるPreload ListをもとにHSTSを利用していることになる．

## Bootstrap MITMへの脆弱性

MITM(man-in-the-middle, 中間者攻撃)の説明は割愛する．RFCの[Bootstrap MITM Vulnerability](https://tools.ietf.org/html/rfc6797#section-14.6)に説明がある．

> Bootstrap MITMの脆弱性は，未知のHSTSホスト(HSTSに対応したWebサーバ)へユーザーがhttpを使って，アドレスを入力してアクセスするか，リンクに従ってアクセスする場合に発生する．原因は，HTTPクライアント(Webブラウザやアプリケーション)が最初に接続先WebサーバとHTTPの通信を試みることにある．攻撃者によりHTTPの通信が改変された場合，ユーザは気づかないうちに攻撃者の用意した攻撃サイトへ誘導されてしまう．

HTTPS対応サイトでも初回にHTTPでアクセスされた場合(例: URLバーへアドレスを直接入力)，ホスト(サーバ)までの経路は平文でやり取りされる．つまり，通信が暗号化により保護されない．よって，平文でやり取りされている通信は中間者攻撃により盗聴や改ざん，なりすましや否認の恐れがある．

# ツール群の対応

## curl

巨大なHSTS Preload Listを内包するのは，多くの使用者に好ましくないのでオプションでPreload Listを指定できる実装がすすめている．現段階ではメインストリームへマージされていない．curl 7.7.0でも確認済み．

- [curl - Roadmap](https://curl.haxx.se/dev/roadmap.html)
- [HTTP Strict Transport Security (HSTS) using libhsts by zagor · Pull Request #2682 · curl/curl](https://github.com/curl/curl/pull/2682)

## wget

1.99.2でChromium用のHSTS Preload List用のオプションが追加された．

- [GNU Wget2 1.99.2 (beta) released](https://lists.gnu.org/archive/html/info-gnu/2019-09/msg00001.html)

1.99.2をビルドしたところ以下のオプションが確認できた．

```shell
$ wget --help | grep hsts
      --hsts                Use HTTP Strict Transport Security (HSTS).
      --hsts-file           Set file for HSTS caching. (default: ~/.wget-hsts)
      --hsts-preload        Use HTTP Strict Transport Security (HSTS).
                              [Not built with libhsts, so not functional]
      --hsts-preload-file   Set name for the HSTS Preload file (DAFSA format).
                              [Not built with libhsts, so not functional]
```

# HSTS Preload ListへWebサイトを追加

- .devドメインや.appドメイン
    - 既にPreload Listに含まれている為，対処は不要
- その他のドメイン
    - `Strict-Transport-Security` ヘッダにpreloadオプションを付与
    - https://hstspreload.org/ で申請

Preload Listに対応した主要サービス

- Twitter(twitter.com)
- Facebook(facebook.com)
- GitHub(github.com)
- YouTube(youtube.com)
- Slack(slack.com)
- WordPress.com(wordpress.com)
- Tumblr(tumblr.com)
- Cybozu(cybozu.com)
- Amazon(www.amazon.co.jp)
- Airbnb(www.airbnb.jp)
- Pinterest(pinterest.jp)
- Instagram(www.instagram.com)

# (2020/06/24追記) govドメインもHSTS Preload Listへ

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">govドメインを全部HSTS Preloadに入れるアナウンス。2020年9月1日から新規ドメインは自動的にPreloadに入れ、将来的にgovのTLD全部を登録する予定。<a href="https://t.co/lcSQE0FXHf">https://t.co/lcSQE0FXHf</a>はいつになるのやら。 / “Making .gov More Secure by Default | DotGov” <a href="https://t.co/mUmDugFGwe">https://t.co/mUmDugFGwe</a></p>&mdash; Shigeki Ohtsu (@jovi0608) <a href="https://twitter.com/jovi0608/status/1275615005992312832?ref_src=twsrc%5Etfw">June 24, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

米国政府系サイトに使われるTLDであるgovもappやdevと同様にHSTS Preload Listに含まれるという．

https://twitter.com/tmyk_kym/status/1389084099537559552

# (2020/10/06追記) newドメインもHSTS Preload Listへ

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">【自分用メモ】.newはTLDごと、HSTSプリロード済み。// Status: new is currently preloaded. - HSTS Preload List Submission <a href="https://t.co/FTkY5yTdjc">https://t.co/FTkY5yTdjc</a></p>&mdash; Yasuhiro Morishita (@OrangeMorishita) <a href="https://twitter.com/OrangeMorishita/status/1287707862588776448?ref_src=twsrc%5Etfw">July 27, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

新たなドメイン `.new` がHSTS Preload Listに追加された．

## その他のドメイン

- `.play`
- `.youtube`
- `.google`
- `.gmail`
- `.chrome`
- `.foo`
- `.android`
- `.search`

## [例外] IPアドレス

Cloudflareの提供するパブリックDNS `1.0.0.1` がHSTS Preload Listに含まれていた．

https://twitter.com/tmyk_kym/status/1389082925396676616

# (2025/05/09 追記) HSTS Preload Listが非推奨に

Xで以下のツイートを見て知った．

https://x.com/330k/status/1909567410488975476

> Many browsers (Chrome, Safari) will automatically upgrade all HTTP navigations to HTTPS, regardless of the domain's HSTS policy. HSTS preloading only provides value when these upgrades fail in the presence of an active attacker. The benefits provided by HSTS preloading are minimal compared to the benefits provided by HSTS. While HSTS is recommended, HSTS preloading is not recommended.
> 
> 出典 https://hstspreload.org/

# 参考資料

- [Strict-Transport-Security - HTTP | MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security#Preloading_Strict_Transport_Security)
- [HTTP Strict Transport Security - The Chromium Projects](https://www.chromium.org/hsts)
- [HSTS Preload List Submission](https://hstspreload.org/)
- [HTTP Strict-Transport-Security (HSTS) - Qiita](https://qiita.com/nyamage/items/11c5bac497a82b8ecaef)
- [HSTS option on .dev domains - Feedback / Usage & Design - Cloudflare Community](https://community.cloudflare.com/t/hsts-option-on-dev-domains/65444)
- [Google makes HTTPS encryption mandatory for its 45 new TLDs](https://blog.nameshield.com/blog/2018/04/19/google-makes-https-hsts-encryption-mandatory-for-its-45-new-tlds/)