AWS ALB 配下で HSTS の設定を行う方法 

# 概要
AWS ALB 配下で HSTS の設定を行う方法を備忘録として残しておきます。
なおこの設定方法は 2019年9月 時のベストプラクティスであり、後に公式対応される可能性もあるので
そこだけご了承ください。

# 背景
皆さんサイトの HTTPS 化は終わってますか? 今更すぎてこの投稿を出すのも恥ずかしいですが、
HTTPS 化に関しての知識が抜けてる部分が僕の中であったので Qiita に投稿しました。

ここでお話したいのは単に HTTPS 化しろよという話ではなく HTTPS 化した際にどのような手順で HTTPS 化したかが重要になります。
今回対象ユーザは下記 2番 のパターンの方です。

1. HTTPS オンリーでサーバを運用している。（問題なし）  
2. HTTP から HTTPS にリダイレクトさせて運用している。(問題ある可能性) 

2番 の設定で HTTPS 化したサイトの場合、後述する HSTS の設定を行わなければセキュアな HTTPS 通信の運用ができているとは言い難い状況なので今すぐ HSTS の設定を行いましょう。


# 結論
下記設定を web サーバに(例は apache の場合)すれば ALB 配下でも HSTS の設定ができます。

``` virtualhost.conf
　<VirtualHost *:80>
　RewriteEngine On
　RewriteCond %{HTTP:X-Forwarded-Proto} =http
　RewriteRule .* https://%{HTTP:Host}%{REQUEST_URI} [L,R=permanent]
　Header always set Strict-Transport-Security "max-age=300; includeSubDomains"
　</VirtualHost>
```

# 環境
今回の検証環境で利用したサービスは下記のとおりです

AWS ALB （Application Load Balancer）
AWS TargetGroup
AWS EC2
WebServer Apache

# 課題
今回の課題は AWS 環境かつ ALB + EC2 の組み合わせで運用している場合に起こる問題です。

下記構成（ALB + TargetGroup + EC2）の場合 HSTS の設定が効かない。
　　ALB (80 443 Listener)
　　　　　　V
　　TargetGroup(80)
　　　　　　|
　　EC2(SecurityGroup 80)

理由は、 HSTS を有効化する header のオプションが 80 番経由で付与できないからです。
header のオプションを追加する設定は apache や nginx などの config から付与するか .htaccess から付与することができます。しかし HSTS の設定を付与する header は必ず 443 番経由の通信で設定しなければならないといった制限があります。これはインターネット技術に関する標準化された文書である RFC の RFC6797 7.2節 にしっかりと書かれています。

> An HSTS Host MUST NOT include the STS header field in HTTP responses conveyed over non-secure transport.

参考 ： https://datatracker.ietf.org/doc/rfc6797/?include_text=1

# HSTS(HTTP Strict Transport Security) とは

HSTS とは HTTP から HTTPS へのリダイレクト途中の通信を改ざんされたり中間者攻撃を防ぐための設定です。 HTTP の通信は改ざんチェックは行われないため HTTPS のリダイレクト途中の通信でサイトに対して攻撃されてしまうと検知するすべがありません。

HSTS を導入するとサーバ側で HTTPS にリダイレクトされるのではなくブラウザ内部で HTTPS へのリダイレクトが行われます。通信の始点であるブラウザから HTTPS 通信することによって通信の途中で HTTP 通信することがありません。

このように HSTS を導入するとこうした中間者攻撃を防ぐことができるため HTTP から HTTPS へリダイレクトする際に一緒に設定することが推奨されています。

HSTS については色々なサイトで説明されてるので詳しくは他のサイトを参照すると良いでしょう。
Wikipedia のサイトを一応リンクさせておきます。
Wikipedia: https://ja.wikipedia.org/wiki/HTTP_Strict_Transport_Security

# 解決方法
ALB を利用している場合にこの HSTS が効かない理由として ALB の仕様上の問題点として下記2点あります。

1. ALB の Listener は 443 と 80 を Listen するが  TargetGroup は 80 番のみにすることがよくある
2. ALB はカスタムヘッダーを付与して返すことができない。

まず 1番ですが ALB のリスナーは 443 と 80 番を Listen するが TargetGroup は管理のしやすさからすべて 80 番に集約させるのが一般的です。その場合起こる問題が HSTS の仕様である 80 番で HSTS を設定するヘッダーを送ることができない問題です。TargetGroup から ALB の通信は 80 番ポートで行うため HSTS のヘッダーが有効にならないと行った問題があります。

これを解決するために TargetGroup も 443 を開けるといった方法もありますが、443 のために全く同じ Virtualhost を 二重管理する必要があるのであまりやりたくありません。

そこで、下記の設定をすることで ALB 環境下でも HSTS の設定を行うことができます。

``` virtualhost.conf
　<VirtualHost *:80>
　RewriteEngine On
　RewriteCond %{HTTP:X-Forwarded-Proto} =http
　RewriteRule .* https://%{HTTP:Host}%{REQUEST_URI} [L,R=permanent]
　Header always set Strict-Transport-Security "max-age=300; includeSubDomains"
　</VirtualHost>
```
これは .htaccess に設定しても問題ありません。
内容は単にリダイレクトの設定を apache で行ってるだけです。

これは HSTS の設定をヘッダーに付与する設定です。これはこう書くものだと思っといてください。

```
Header always set Strict-Transport-Security "max-age=300; includeSubDomains"
```

RewriteCond の条件には必ず下記の ALB の拡張ヘッダーである `X-Forwarded-Proto = http` をつけてください。これをつけないとリダイレクトのループが起こります。 
この条件は、ALB に来たアクセスのプロトコルが http か https を判定する条件です。ALB に来たアクセスが http のみ https にリダイレクトさせるといった意味になります。


```
　RewriteCond %{HTTP:X-Forwarded-Proto} =http
```

どうやら ALB + TargetGroup 環境では ALB と TargetGroup を含めた全体が HTTPS で通信されれば
HTTPS として通信されるとみなしてくれるみたいなので HSTS の設定が効くようになります。

HSTS の設定が効いているかは下記の Chrome の機能で確認できます。

1. chrome://net-internals/#hsts にアクセスする
2. Query HSTS/PKP domain にドメインを入力して「Query」ボタンをクリック
3. 「Found」 と出たら設定が効いています。

または、ブラウザの Network タブを開いて 「Status Code」 が 「Internal Redirect 307」 になっており HTTPS にリダイレクトされていれば設定が効いています。


ここでリダイレクトといえば ALB 側で https にリダイレクトできる設定があるけどと思った方はさすがです。
実は apache や .htaccess にリダイレクトの設定を記述する他にも ALB 側でリダイレクトする設定もあります。

ここで 2番の ALB では現在カスタムヘッダーを付与して通信を返すオプションが無いという仕様が問題になります。現状では HSTS のためのカスタムヘッダーを ALB が付与して返すと行ったことが現時点ではできない仕様になっております。


この件に関しては AWS 側も承知済みの件で、対応要望が多いためいずれ ALB ネイティブで対応する可能性があるとの情報もあります。


地味にこの件に関しては ALB ネイティブで対応してくれるとありがたい気がします。HSTS 以外にも ALB 側でカスタムヘッダーを付与できれば .htaccess の運用もいらなくなるしいいことがありそうです。


# 最後に
HSTS について話してきましたが、この設定をした上で更にセキュリティを高めたい場合は HSTS の Preload 設定を行う必要があります。実は上記設定をしても有効になるのは 2回目のアクセス以降であって 1回目のアクセス時には HSTS が有効になりません。
この穴を防ぐために HSTS Preload 設定を行う事ができます。

詳しくは  HSTS Preload を調べてみてください。


以上細かいけど重要そうな知識の話でした。