セキュリティ
セキュリティヘッダーとは?それぞれの役割と追加方法
セキュリティヘッダーは、すべてのブラウザに組み込まれた保護機能を有効にします。それぞれの役割、安全な初期値、主要なサーバーやプラットフォームでの追加方法を紹介します。
このページの内容
セキュリティヘッダーとは、ブラウザにもともと備わっている保護機能を有効にするよう指示する HTTP レスポンスヘッダーです。HTTPS でしか接続しない、想定外の場所から来たスクリプトは実行しない、他のサイトにこのページをフレーム内で表示させない、といった指示を出します。脆弱なコードそのものを直してくれるわけではありませんが、クロスサイトスクリプティング、クリックジャッキング、プロトコルのダウングレードといったよくある攻撃を、はるかに成功しにくくし、成功した場合の被害も抑えます。
サイトが送信しているヘッダーを確認する方法
- ブラウザで:開発者ツールを開いて「ネットワーク」タブに移動し、ページを再読み込みします。最初の(ドキュメントの)リクエストをクリックして、レスポンスヘッダーを確認します。
- ターミナルから:
curl -I https://example.comを実行するとヘッダーが表示されます。 - チェッカーで:Rudra の無料ウェブサイトセキュリティチェッカーは、サイトが HTTPS を使い、暗号化されていない HTTP を HTTPS にリダイレクトしているか、TLS 証明書が有効で期限切れが迫っていないかを確認し、HSTS、Content-Security-Policy、X-Frame-Options(または CSP の
frame-ancestors)、X-Content-Type-Options、Referrer-Policy、Permissions-Policy の値を読み取ります。さらに、ソフトウェアのバージョン番号を明かしてしまうServerヘッダーやX-Powered-Byヘッダーを検出し、Cookie のフラグと CORS も確認します。
ヘッダーが存在するだけでは、合格とは言えません。どこからのスクリプトでも許可する Content-Security-Policy は、存在はしていてもほとんど何も守りません。そのため Rudra は値も解析します。HSTS の max-age が180日未満である、CSP の script-src に 'unsafe-inline' や * が含まれている、X-Frame-Options の値が無効である、といった場合は「弱い」と報告されます。以下のセクションを読んで、ご自身の設定値を評価してみてください。
各ヘッダーの解説
Strict-Transport-Security(HSTS)
誰かが http:// と入力したり古いリンクをたどったりした場合でも、指定した期間はそのドメインに HTTPS で接続するようブラウザに指示します。これにより、ネットワーク上の攻撃者が最初の安全でないリクエストを傍受できる隙がなくなります。よく使われる値は Strict-Transport-Security: max-age=63072000; includeSubDomains(2年間)です。
- 最初は300秒などの短い
max-ageから始め、すべてのページが HTTPS で動作すると確信できてから値を引き上げます。 includeSubDomainsは、忘れているかもしれない古いものも含め、すべてのサブドメインが HTTPS で配信されている場合にだけ追加します。preloadフラグを付けてブラウザのプリロードリストに登録申請すると、そのドメインでの HTTPS 接続がブラウザ自体に組み込まれます。元に戻すのは難しく時間もかかるので、最後に、よく考えたうえで追加してください。- ブラウザが HSTS を受け入れるのは、HTTPS 経由で受信した場合だけです。
Content-Security-Policy(CSP)
ページがスクリプト、スタイル、画像、フォント、フレームをどこから読み込んでよいかを列挙したものです。攻撃者がスクリプトを注入できたとしても、適切な CSP があればブラウザはそれを実行しません。ここで紹介する中で最も強力なヘッダーであり、最も設定を誤りやすいヘッダーでもあります。シンプルなサイト向けの妥当な出発点は次のとおりです。
Content-Security-Policy: default-src 'self'; img-src 'self' data:; object-src 'none'; base-uri 'self'; frame-ancestors 'none'
このポリシーは、リソースの読み込みを自サイトのオリジン(とインラインの data: 画像)だけに限定し、プラグインをブロックし、注入された <base> タグが相対URLの向き先を変えるのを防ぎ、フレームへの埋め込みを禁止します。実際のサイトではアクセス解析、フォント、埋め込みコンテンツ、決済サービスを使っており、それぞれを明示的に許可する必要があります。また、インラインスクリプトは nonce かハッシュで許可しない限りブロックされます。導入するときは、まず Content-Security-Policy-Report-Only を使いましょう。ブラウザは何もブロックせずに、違反をコンソールに(レポート用エンドポイントを設定していればそこにも)報告するので、ポリシーを強制する前に調整できます。
X-Content-Type-Options
X-Content-Type-Options: nosniff は、ブラウザがファイルの種類を推測して、たとえばアップロードされたテキストファイルをスクリプトとして実行してしまうのを防ぎます。設定項目はなく、サーバーが正しい Content-Type ヘッダーを送信している限り、何かが壊れることはまずありません。すべての場所に追加しましょう。
クリックジャッキング対策:frame-ancestors と X-Frame-Options
クリックジャッキングは、あなたのサイトを別のサイトのフレーム内に隠して表示し、利用者にその上の何かをクリックさせる手口です。現在の標準的な対策は、CSP ディレクティブの frame-ancestors 'none'(フレームへの埋め込みを一切許可しない)または frame-ancestors 'self'(自サイトのページにだけ許可する)です。従来からある X-Frame-Options: DENY や SAMEORIGIN は古いブラウザで同じ役割を果たし、両方を送信しても害はありません。特定のパートナーサイトにページを埋め込む必要がある場合は、そのオリジンを frame-ancestors に列挙します。
Referrer-Policy
訪問者がリンクをたどったりリソースを読み込んだりするときに、現在のURLのうちどこまでを他のサイトに送信するかを制御します。URLには、外に漏らしたくない検索語、ID、トークンが含まれていることがあります。Referrer-Policy: strict-origin-when-cross-origin を指定すると、自サイト内では完全なURLを送信し、他のサイトにはオリジン(https://example.com)だけを送信し、HTTPS から HTTP へ移動するときには何も送信しません。最近のブラウザはすでにこれを既定値としていますが、明示的に設定しておくと挙動が統一されます。
Permissions-Policy
サイトが使っていない強力なブラウザ機能を無効にし、自サイトのコードも、埋め込まれたサードパーティも、その機能を要求できないようにします。カメラ、マイク、位置情報を必要としないサイトなら、Permissions-Policy: camera=(), microphone=(), geolocation=() と指定します。
削除する、または設定しなくてよいヘッダー
- バージョンを明かすヘッダー:バージョン番号を含む
ServerやX-Powered-Byの値は、どのソフトウェアのどのバージョンを狙えばよいかを攻撃者に正確に教えてしまいます。ヘッダーごと削除するか、バージョンを取り除きましょう(nginx ではserver_tokens off;)。 - X-XSS-Protection:最近のブラウザからはすでに削除されたフィルターを制御するためのヘッダーでした。これに頼ってはいけません。省略するか、
0に設定します。
セキュリティヘッダーの追加方法
nginx
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;add_header X-Content-Type-Options "nosniff" always;add_header Referrer-Policy "strict-origin-when-cross-origin" always;add_header X-Frame-Options "DENY" always;
always フラグを付けると、エラーレスポンスにもヘッダーが追加されます。継承には注意が必要です。location ブロックに add_header ディレクティブが1つでもあると、そのブロックは server レベルで定義したヘッダーを継承しなくなるため、該当するURLからヘッダーが何の警告もなく消えてしまいます。同じヘッダーを繰り返し書くか、共通ファイルにまとめて include で読み込みましょう。
Apache
mod_headers を有効にしたうえで、バーチャルホストまたは .htaccess に Header always set X-Content-Type-Options "nosniff" と記述します。他のヘッダーも、Header always set Referrer-Policy "strict-origin-when-cross-origin" のように同じ書き方で追加します。
Next.js
next.config.js で、すべてのパスに対してヘッダーを返します。async headers() { return [{ source: '/:path*', headers: [{ key: 'X-Content-Type-Options', value: 'nosniff' }, { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' }] }]; } のように記述します。nonce を使う CSP の場合は、Next.js のドキュメントで説明されているとおり、ミドルウェアでリクエストごとにヘッダーを生成してください。
Netlify、Cloudflare Pages などのホスティングサービス
これらのホスティングサービスは、公開フォルダーにある _headers ファイルを読み込みます。1行に /* のようなパスのパターンを書き、その下にインデントして、X-Content-Type-Options: nosniff のようにヘッダーを1行に1つずつ書きます。Vercel では、vercel.json の headers セクションがこれに相当します。CDN を使っている場合は、たいてい CDN 側でもヘッダーを追加できます。
安全に導入する手順
- まず、リスクの低いヘッダーから追加します。
X-Content-Type-Options、Referrer-Policy、Permissions-Policy、そしてクリックジャッキング対策です。 - HSTS を短い
max-ageで有効にし、数週間かけて値を大きくしていきます。 - CSP をレポート専用モードで導入し、報告された問題を修正してから強制します。
- サードパーティが関わる操作の流れをテストします。ログイン、購入手続きと決済フレーム、埋め込み動画、地図、チャットウィジェット、アクセス解析などです。
- セキュリティチェッカーで再確認し、新しいサードパーティ製ツールを追加するたびにもう一度確認します。
よくある間違い
- 他のサイトの厳格な CSP をコピーして、決済、アクセス解析、埋め込みコンテンツを壊してしまう。
'unsafe-inline'、'unsafe-eval'、ワイルドカードだらけの CSP を書く。存在チェックには通りますが、ほとんど何も守れません。- すべてのサブドメインで HTTPS の準備が整う前に、HSTS の
preloadを追加する。 - HTML の
<meta>タグでヘッダーを設定する。この方法で機能するのは CSP の一部のディレクティブだけで、HSTS、frame-ancestors、X-Frame-Optionsは meta タグでは無視されます。 - アプリケーションとプロキシの両方でヘッダーを追加し、レスポンスに重複した値や矛盾する値が含まれてしまう。
- ソフトウェアの更新、入力値の検証、出力のエスケープの代わりになるものとしてヘッダーを扱う。
ヘッダーとヘッダーチェックではカバーできないこと
ヘッダーは防御層の一つにすぎません。ヘッダーをチェックしても、古いプラグイン、弱い管理者パスワード、インジェクションの欠陥、公開されたままのバックアップファイルは見つかりません。Cookie も別途見直す価値があります。セッション Cookie には Secure、HttpOnly、SameSite の各属性を付けるべきです。Rudra のセキュリティチェッカーは、ページ自体のレスポンスが設定する Cookie について、これらのフラグを報告します(名前だけで、値は決して報告しません)。詳しくは Cookie のセキュリティを確認する方法を、パッシブチェックでわかることとわからないことについてはウェブサイトのセキュリティを確認する方法をご覧ください。サイトの健全性をより幅広く把握したい場合は、総合的なウェブサイト監査を実行してください。
よくある質問
最初に追加すべきセキュリティヘッダーはどれですか?
まずサイト全体が HTTPS で配信されていることを確認し、そのうえで X-Content-Type-Options: nosniff、Referrer-Policy、クリックジャッキング対策を追加します。これらが何かを壊すことはまずありません。次に HSTS を短い max-age で追加し、Content-Security-Policy は最後に、まずレポート専用モードで導入します。
セキュリティヘッダーは SEO に影響しますか?
直接は影響しません。HTTPS そのものは Google の軽微なランキングシグナルですが、CSP や X-Content-Type-Options のようなヘッダーは順位に影響しません。これらが守るのは訪問者とサイトの評判であり、そちらのほうが重要です。
X-Frame-Options はもう使われていないのですか?
より柔軟な CSP の frame-ancestors ディレクティブに取って代わられました。両方を送信しても害はなく、古いブラウザにも対応できます。
meta タグでセキュリティヘッダーを設定できますか?
一部だけです。Content-Security-Policy は meta タグで設定できますが、frame-ancestors とレポート機能は使えません。HSTS、X-Frame-Options、その他ほとんどのセキュリティヘッダーは、実際の HTTP レスポンスヘッダーとして送信した場合にだけ機能します。
厳格な Content-Security-Policy を設定するとサイトが壊れますか?
ページに必要なスクリプト、スタイル、フレームをブロックしてしまうと、壊れる可能性があります。だからこそ、まず Content-Security-Policy-Report-Only から始め、報告された違反を確認してポリシーを調整し、そのあとで初めて強制すべきなのです。