第6回 Cloudflareのセキュリティヘッダーを設定する―AstroサイトのHTTPレスポンスを見直す

CloudflareのResponse Header Transform RulesとHSTS、Always Use HTTPSを使ってbringain.comのHTTPレスポンスを見直した。Security Headersの評価がFからAに変わるまでと、HTTPが200 OKのままだったつまずきも含めて記録する。

執筆:ゆまラボ運営者

公開:
第6回 Cloudflareのセキュリティヘッダーを設定する―AstroサイトのHTTPレスポンスを見直す

第5回では、記事公開後にXへ流す運用をWeb Intentで半自動化した。

サイト側の設定へ戻り、CloudflareでHTTPレスポンスヘッダーを追加する。以前、Astroサイトのセキュリティヘッダーを確認した記事で、bringain.comにどのヘッダーが付いているかを確認した。今回は確認だけで終わらせず、実際にCloudflare側へ設定する。

作業内容は大きく3つある。

  • Response Header Transform Rulesで4つのヘッダーを追加する
  • HSTSを有効にする
  • HTTPアクセスをHTTPSへリダイレクトする

途中で、HSTSまで設定したあともHTTPアクセスが200 OKのままになっていることに気付いた。Cloudflare側に別の設定が残っていたため、そこも含めて実際の作業順に残す。

設定前のレスポンスヘッダーを確認する#

最初にPowerShellからHTTPS側のレスポンスヘッダーを確認した。

curl.exe -I https://bringain.com/

設定前のbringain.comのHTTPレスポンスヘッダー

この時点では、レスポンスにCloudflare由来のヘッダーは返っているものの、今回確認したかった次のヘッダーは見当たらなかった。

  • Strict-Transport-Security
  • Content-Security-Policy
  • X-Frame-Options
  • X-Content-Type-Options
  • Referrer-Policy
  • Permissions-Policy

続いてSecurity Headersでbringain.comをスキャンした。

Security Headersで設定前のbringain.comを確認した結果

評価はF

設定前に不足していた6つのセキュリティヘッダー

画面上でも6項目すべてがMissing Headersとして表示された。

ここでCSPまで一度に入れることはしなかった。ゆまラボではGoogle AnalyticsやAdSenseなど外部リソースを使っている。CSPは許可する読み込み元を細かく決めるため、値を適当に追加すると計測や広告、外部スクリプトを止める可能性がある。

CSPは保留し、それ以外を先に設定する。

Response Header Transform Rulesで4つのヘッダーを追加する#

Cloudflareでは、Response Header Transform Rulesを使って訪問者へ返すHTTPレスポンスヘッダーを追加・上書きできる。

公式ドキュメントでも、Set staticは同名ヘッダーがあれば値を置き換え、存在しなければ新しく追加する動作になっている。

ルール名はSecurity Headers。すべての受信リクエストへ適用した。

設定した値は次の4つ。

X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()

CloudflareのResponse Header Transform Ruleへ4つのヘッダーを設定した画面

今回のルールでは、カメラ、マイク、位置情報の利用も許可しない設定にした。

デプロイ後、同じコマンドでもう一度確認する。

curl.exe -I https://bringain.com/

Transform Rule設定後に4つのヘッダーが追加されたレスポンス

レスポンスには次の4行が追加された。

Permissions-Policy: camera=(), microphone=(), geolocation=()
Referrer-Policy: strict-origin-when-cross-origin
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN

Cloudflareのルール作成画面だけでなく、実際の公開URLに対するレスポンスで確認できたので、Transform Ruleは反映されている。

HSTSはエッジ証明書から有効にする#

Strict-Transport-SecurityはTransform Ruleへ追加せず、CloudflareのHSTS設定を使った。

Cloudflareのエッジ証明書にはHSTS専用の設定があり、公式の案内でもHTTPSが正常に利用できることを確認してから有効にする手順になっている。

HSTSはこの設定で有効化した。

HSTS: 有効
Max Age: 6か月
includeSubDomains: OFF
Preload: OFF
No-Sniff Header: OFF

CloudflareでHSTSを6か月に設定した画面

includeSubDomainsは有効にしていない。サブドメインまで一括でHSTS対象にすると、HTTPSに対応していないサブドメインがあった場合にアクセスできなくなるためだ。

Preloadも使わない。Cloudflareの案内では、Preloadを使う場合はより長いMax Ageなどの前提がある。

No-Sniff HeaderはOFF。X-Content-Type-Options: nosniffはTransform Ruleで追加済みなので、別設定との重複を避けた。

保存後にHTTPS側を確認すると、今度はHSTSも返るようになった。

HSTS設定後にStrict-Transport-Securityを確認したレスポンス

Strict-Transport-Security: max-age=15552000

15552000秒は、Cloudflareで選択した6か月の設定として返っている。

Security Headersの評価はFからAへ変わった#

ここでSecurity Headersをもう一度実行した。

セキュリティヘッダー設定後にSecurity HeadersでA評価になった画面

評価はFからAへ変わった。

設定前に不足していた6項目のうち、次の5つは緑の判定になっている。

  • X-Frame-Options
  • Strict-Transport-Security
  • Permissions-Policy
  • Referrer-Policy
  • X-Content-Type-Options

残ったのはCSPだけ。

設定後にContent-Security-PolicyだけがMissingとして残った画面

ここは無理に埋めない。

CSPは外部スクリプトや画像、フレームなどの読み込み元を制御する。現在のゆまラボで使っているGoogle AnalyticsやAdSense、今後追加する外部サービスまで含めて許可元を確認してから設定する必要がある。

Security Headersのスコアだけを上げるために、動作確認なしでCSPを追加する方が危険なので、今回の作業範囲から外した。

HSTSを設定してもHTTPは200 OKのまま#

ここで一度つまずいた。

HSTSまで有効にしたのにHTTPが200 OKのままなのは、最初に見たとき少し違和感があった。

HTTP側のレスポンスを確認するため、次を実行していた。

curl.exe -I http://bringain.com/

HTTPでアクセスしたとき200 OKのままだったレスポンス

結果はHTTP/1.1 200 OK

HSTSまで有効にしたので、HTTPアクセスもHTTPSへ送られる状態になったように見えたが、Cloudflare側のHTTPレスポンスそのものはリダイレクトされていない。

HSTSとHTTP→HTTPSリダイレクトは同じ設定ではない。

HSTSはHTTPSレスポンスにStrict-Transport-Securityを付け、対応ブラウザへHTTPS利用を記憶させる。一方、HTTPリクエストへ3xxを返してHTTPSへ移動させるのは別の処理になる。

Cloudflareの設定を見直すと、常に HTTPS を使用(Always Use HTTPS)がまだ有効になっていなかった。

Always Use HTTPSを有効にする#

CloudflareのAlways Use HTTPSは、HTTPで届いたリクエストをHTTPSへリダイレクトする機能になっている。

Cloudflareの画面から常に HTTPS を使用を有効にした。

Cloudflareで常にHTTPSを使用を有効にした画面

ここは、最初から設定済みだったことにはしない。

実際にはセキュリティヘッダーとHSTSを設定した後、HTTP側が200 OKのままなのを見て追加確認した設定だ。

有効化後、同じHTTP URLを再度確認した。

curl.exe -I http://bringain.com/

Always Use HTTPS有効化後にHTTPからHTTPSへの301を確認した画面

今度は結果が変わった。

HTTP/1.1 301 Moved Permanently
Location: https://bringain.com/

HTTPでアクセスした場合に、HTTPS側へリダイレクトされることを確認できた。

この確認を入れなければ、Security HeadersでA評価になった時点で作業完了としていた可能性がある。外部の評価結果だけでなく、実際のHTTPレスポンスをcurlで確認しておく意味があった。

最終的なヘッダー設定#

最後に、設定結果を表で確認する。

横にスクロールできます
項目設定・確認結果
X-Content-Type-Optionsnosniff
X-Frame-OptionsSAMEORIGIN
Referrer-Policystrict-origin-when-cross-origin
Permissions-Policycamera=(), microphone=(), geolocation=()
Strict-Transport-Securitymax-age=15552000
Always Use HTTPS有効
HTTPアクセス301 Moved PermanentlyでHTTPSへ移動
Security HeadersFA
Content-Security-Policy今回は未設定

今回の作業で変更したのはCloudflare側の設定で、Astroのコードには手を入れていない。

設定前は6つのヘッダーが不足し、Security HeadersではF評価だった。Response Header Transform Rulesで4つを追加し、HSTSを有効にしたところA評価まで変わった。さらにHTTPアクセスを確認すると200 OKのままだったため、残っていたAlways Use HTTPSも有効化し、最後に301 Moved PermanentlyとHTTPSへのLocationを確認した。

CSPは未設定のまま残している。ここは現在利用している外部リソースを確認したうえで、別の作業として扱う。