このツールでできること
レスポンスヘッダーは、ページをどう扱うかをブラウザに伝えます。HTTPSを必須にするか、どのスクリプトの実行を許すか、どこからフレームに埋め込んでよいか、といったことです。このチェックは、Cloudflareのネットワーク上にあるiseeu.ccのサーバーから、入力されたURLにリクエストを送り(まずHEAD、サーバーがHEADを拒否したらGET)、レスポンスの本文は読まずに捨てて、返ってきたセキュリティヘッダーを評価します。
評価する項目は次のとおりです。
- Strict-Transport-Security(HSTS)。このホストでは
max-age秒のあいだHTTPSだけを使うよう、ブラウザに指示します。これにより、次回以降のアクセスで、共用Wi-Fiなどで乗っ取られかねない平文のHTTPリクエストが送られることはなくなります。1年(31536000)以上なら良好とし、includeSubDomainsとpreloadの有無も表示します。平文のHTTPで送られたこのヘッダーは無視されます。 - Content-Security-Policy(CSP)。スクリプトなどのリソースをどこから読み込んでよいかを指定します。攻撃者がコメント欄に
<script>タグを紛れ込ませても、script-src 'self'があれば実行されません。script-srcに'unsafe-inline'や'unsafe-eval'があると、注入されたインラインコードやeval()が結局実行されてしまうので、守りが弱くなります。frame-ancestorsもチェックします。 - クリックジャッキング対策。悪意のあるページが、あなたのページを透明なフレームに入れておとりのボタンの上に重ねると、訪問者のクリックがあなたのページに届いてしまいます。
X-Frame-Options: DENYまたはSAMEORIGIN、あるいはCSPのframe-ancestors 'none'または'self'で防げ、どちらかがあればこの項目は満たされます。 - X-Content-Type-Options: nosniff。宣言されたContent-Typeをブラウザに信用させます。これにより、JavaScriptを仕込んだテキストファイルを誰かがアップロードし、それが
text/plainで配信されても、scriptタグ経由で実行されることはありません。 - Referrer-Policy。
strict-origin-when-cross-originにすると、/reset?token=abc123にあるページは、外部のサイトにRefererヘッダーでスキームとホストだけを伝え、トークンは伝えません。 - Permissions-Policy。使わないブラウザ機能を、そのページと、そこに埋め込まれたすべてのものに対して無効にします。
camera=(), microphone=(), geolocation=()なら、乗っ取られた広告フレームやスクリプトは、これらの機能の利用許可を求めることすらできません。 - Cross-Origin-Opener-Policy(COOP)。
same-originにすると、ページは独自のブラウジングコンテキストグループに入ります。そのため、このページを開いた別サイトのウィンドウや、このページが開いた別サイトのウィンドウは参照を失い、ページを操作することも探ることもできなくなります。
評価には含めず、表示だけするもの:ServerやX-Powered-Byの値(Apache/2.4.41 (Ubuntu)やPHP/7.4.3など。サイトと既知の脆弱性を結び付けやすくしてしまいます)と、各Set-Cookieの属性(SecureはHTTPSでのみ送信、HttpOnlyはJavaScriptから見えなくする、SameSiteはクロスサイトのリクエストでの送信を制限)です。
評価は経験則による要約で、セキュリティ監査ではありません。ヘッダーは防御の1つの層にすぎず、SQLインジェクションやパッチの当たっていないCMSを直すことはできません。
使い方
http://またはhttps://で始まる公開URLを、省略せずに入力します。- チェックを実行します。5秒たっても終わらなければ打ち切ります。
- リダイレクトの経路を確認します。リダイレクトは5回までたどり、各段階のステータスコードとLocationを表示します。
- 最終的なステータスコード、評価、レスポンスヘッダーの一覧を確認します。
使えるポートは80と443だけです。プライベート、ループバック、リンクローカル、キャリアグレードNAT、その他の予約済みのアドレスは拒否し、localhostや、.localや.internalの下にある名前も拒否します。iseeu.cc自身も、リダイレクトでここに戻ってくる場合を含めて拒否します。同じサーバーを呼び返すことになるからです。このサイトのヘッダーは、代わりにcurl -sI https://iseeu.cc/で確認できます。チェックはIPアドレスごとに1分あたり10回までです。URLは保存もログ記録もしません。
対象のサイトから見ると、リクエストはあなたではなくCloudflareから来ます。そのため、ボットチェック、国によるリダイレクト、HEADとGETで扱いを変えるサーバーなどによって、結果が変わることがあります。
こんなときに
- デプロイの後に。プロキシやCDNの変更でヘッダーが落ちていないかを確かめます。ロードバランサーを入れ替えたらHSTSが消えていた、といったケースです。
- リダイレクトの整理。http://が1回でhttps://に移るか、ドメイン直下とwwwが1つのアドレスにまとまるかを確認します。
- 外部サービスの確認。取引先のログインページや決済ページを埋め込む前に、そもそもフレームへの埋め込みを許しているかを確かめます。
- バージョン情報の漏れ。正確なバージョンを名乗るServerやX-Powered-Byのヘッダーを見つけます。
- Cookieの点検。監査で指摘される前に、セッションCookieにSecure、HttpOnly、SameSiteが付いているかを確かめます。
- CSPの導入。report-onlyモードを終えた後、強制するポリシーが有効になっていて、'unsafe-inline'を含んでいないかを確認します。
まず設定しておきたいヘッダー
自前のスクリプトとスタイルを配信するサイトなら、次の組み合わせから始めるのが妥当です。
Strict-Transport-Security: max-age=31536000; includeSubDomains
Content-Security-Policy: default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(), microphone=(), geolocation=()
Cross-Origin-Opener-Policy: same-originX-Frame-Optionsは、古いブラウザのためにframe-ancestorsと同じ指定を重ねています。このCSPはインラインスクリプト、onclickのようなインラインのイベントハンドラー、インラインスタイルをブロックするので、強制する前にテストしてください。自分のページの中でこのサイトをフレームに入れている場合は、代わりに'self'とSAMEORIGINを使います。
CSPはreport-onlyモードで導入する
ポリシーをContent-Security-Policy-Report-Onlyとして送ると、ブラウザは何もブロックせず、違反をコンソールと、設定したレポートの送信先に記録します。通常のトラフィックでしばらく動かし、見つかった問題を直してから、ヘッダー名を切り替えます。緩いポリシーを強制しながら、より厳しいポリシーを並行して試すこともできます。report-onlyのヘッダーだけでは、誰も守られません。
HSTSのプリロードは簡単には取り消せない
preloadを付けてドメインを登録すると、Chromeに組み込まれ、Firefox、Safari、Edgeでも使われているリストに載ります。ブラウザは初回のアクセスでも平文のHTTPを使わなくなります。このリストはincludeSubDomainsと1年以上のmax-ageを求めるので、忘れられたイントラネットのホストやプリンターの管理画面に至るまで、すべてのサブドメインが有効なHTTPSを提供しなければなりません。リストからの削除は、利用者がブラウザを更新して初めて行き渡るので、時間がかかります。まずは300のような短いmax-ageで始め、何も壊れないことを確かめてから値を上げ、プリロードは最後にしてください。
X-XSS-Protectionは送らなくてよい
このヘッダーが制御していたブラウザのXSSフィルターは、もうありません。Chromeは2019年にXSS Auditorを削除し、Edgeもフィルターを廃止し、Firefoxにはもともとありませんでした。しかもこのフィルターは、狙ったスクリプトを止めさせる目的で悪用されることがありました。X-XSS-Protection: 0を送るか何も送らずに、CSPに任せてください。
curlで確認する
curl -sI https://iseeu.cc/
curl -sIL http://iseeu.cc/
curl -s -D - -o /dev/null https://iseeu.cc/1つ目は、1回のHEADレスポンスのヘッダーを表示します。リダイレクト自体のヘッダーも含まれますが、これはこのページのリダイレクト一覧には出ません。2つ目はリダイレクトをたどり、各レスポンスを表示します。3つ目はGETを送って本文を捨てるので、HEADを別扱いするサーバーに使えます。1つのヘッダーだけを見たいときは| grep -i strict-transportを付けます。ヘッダー名は大文字と小文字を区別せず、HTTP/2では小文字で送られます。
よくいただく質問
A+と出れば、サイトは安全だと考えてよいですか?
いいえ。評価は、ブラウザ側で起きる一部の攻撃を難しくするレスポンスヘッダーを、いくつかまとめて見たものにすぎません。パッチの適用、認証、アクセス制御、インジェクションの不具合、秘密情報の保管方法については何も示しません。A+のサイトでも不備のあるAPIからデータが漏れることはありますし、評価が低くてもきちんと運用されているサイトもあります。1つの層をざっと確かめるものと考え、監査の代わりにはしないでください。
自分のブラウザで確認したヘッダーと、ここに出る内容が一致しないのはなぜですか?
リクエストはあなたの端末ではなくCloudflareのネットワークから送られ、サーバーがHEADを拒否しない限りHEADリクエストです。多くのサイトは、国、ボットらしく見えるかどうか、リクエストメソッドによって応答を変えます。ボットチェック、地域によるリダイレクト、HEADを別に処理するフレームワークは、いずれも違うヘッダーが返る原因になります。比べたいときは、自分のマシンからcurlを実行してください。
自宅や社内ネットワークにあるサーバーもチェックできますか?
できません。チェッカーが接続するのはポート80と443だけで、プライベート、ループバック、リンクローカル、キャリアグレードNATのアドレス、その他の予約済みの範囲、そしてlocalhostや、.localや.internalで終わる名前は拒否します。他人のファイアウォールの内側にあるマシンに届く手段として使われないようにするためです。内部のホストを調べるときは、そのネットワーク内のマシンからcurl -Iを実行してください。
チェックしたURLはどこかに記録されますか?
URLは保存もログ記録もしません。iseeu.ccはIPアドレスや検索内容のログを残さず、訪問者のデータベースも持たず、Cookieも使いません。チェック対象のサイトにはリクエストが届きますが、それはあなたのIPアドレスからではなく、Cloudflareのネットワークから届きます。
HTMLのmetaタグに書いたセキュリティ設定も読み取られますか?
読み取られません。チェッカーはレスポンスヘッダーだけを読み、本文は読まずに捨てるため、meta http-equivタグに書いたポリシーは見えません。ブラウザもmetaタグには制限を設けていて、その方法で指定したCSPではframe-ancestorsが無視され、report-onlyモードも使えません。HSTSとX-Frame-Optionsは、metaタグではまったく無視されます。これらはすべて、本物のHTTPヘッダーで送るのが確実です。
リダイレクトが何段も続くサイトや、応答の遅いサーバーはどうなりますか?
リダイレクトは5回までたどり、各段階のステータスコードとLocationを表示します。5秒たっても終わらなければ打ち切ります。それ以上の段階が必要なチェーンは、たいてい設定ミスの表れで、たとえばhttpとhttps、あるいはドメイン直下とwwwの間で訪問者を行ったり来たりさせているケースです。リダイレクトが1段増えるごとに、実際の訪問者もページの読み込みが始まる前に1往復ぶん待たされます。
評価は、1か所から送った1回のリクエストに対するレスポンスヘッダーだけを見たものです。サイト全体のセキュリティを判定するものではありません。次に何を調べるかを決める手がかりとして扱ってください。