はじめに
こちらは、ZOZOテクノロジーズその2 Advent Calendar 2018 24日目の記事です。
今回は、Lambda@Edgeを使って、CloudFrontにHSTS Preloadを導入してみます。
HSTS Preloadとは
HSTS is 何
HSTS(Hypertext Strict Transport Security)は、Webサーバがもつレスポンスヘッダの一種で、「このサーバで接続するときには必ずHTTPSでアクセスしてね」というメッセージをWebブラウザに伝える働きを持っています。
具体的には Strict-Transport-Security: max-age=31536000;
のようにmax-ageをもたせることで、ブラウザにこの規定の時間がすぎるまではHTTPSを強制化するよう働きかけます。
これによって、仮にユーザが初回HTTPで通信しに来た場合(URLバーでhttp://~で来た場合)も次回以降からはデフォルトでHTTPS通信となり、通信のオーバーヘッドが削減できるというメリットがあります。
HSTSのpreload属性
しかし、HSTSは一度サーバに接続していないと有効にならないという問題もあり、これを解決すべく作られたのが、preload属性です。
HSTSのレスポンスヘッダに Strict-Transport-Security: max-age=63072000; includeSubdomains; preload
を持たせた状態でGoogleが公開している登録フォームにアクセスすることで、preloadを有効にする準備が整います。
どうなってるのか
ざっくり言うとこんな感じです。
- フォームに登録する
- preloadの一覧が入ったJSONに自分のドメインがしばらくすると追加される
- Chromeなどの主要ブラウザがアップデートされたタイミングで、JSONに自分のドメインが追加され、ブラウザ上でpreloadリストに加わる
こうすることで、主要ブラウザに「あらかじめHTTPS通信を強制するサイト」として、自分のドメインを認識することができるようになります。
CloudFrontでの問題点
CloudFrontでは、残念ながらHTTPヘッダをきれいに扱う仕組みが提供されていません。また、S3にHSTSをpreload付きで渡すのも、現状不可能です。
そこで登場するのが、Lambda@Edgeです。
Lambda@Edgeとは
Lambda@Edgeは、CloudFrontのルール定義にLambda(Node.js)を使えるサービスです。詳細については、弊社テックブログにも書きましたので、そちらをご覧ください。
実際のコード
'use strict';
exports.handler = (event, context, callback) => {
const response = event.Records[0].cf.response;
const headers = response.headers;
//Set new headers
headers['strict-transport-security'] = [{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubdomains; preload'
}];
callback(null, response);
};
こちらのコードをオリジンレスポンスに対して仕込んであげることで、オリジンからのコンテンツ返却に合わせた形でHSTSをかぶせることができます。
反映が確認できたら、Googleの登録フォームにて該当ドメインの申請をしてあげましょう。
なお、HSTS preloadではmax-ageに下限値があることと、includeSubdomainsも強制化される点があります。ご注意ください。
反映が完了すると、下記のようにpreloadのリストがすべてのブラウザで有効になることがわかります。なお、こちらの反映にもしばらくの時間を有するため、ご注意ください。