この記事で分かること
- HSTS、CSP、X-Frame-Optionsなど、主要なセキュリティヘッダーの役割と推奨値
- Apache(.htaccess)、nginx、WordPressで使える設定コード
- HSTSとCSPを、サイトを壊さずに入れる段階導入の手順
- 設定の落とし穴と、curlや開発者ツールでの確認方法
要点は三つです。一つ目に、セキュリティヘッダーは「このページはこう扱ってほしい」というブラウザへの指示で、サーバー側の設定だけで追加できます。二つ目に、すぐ入れても問題が出にくいもの(X-Content-Type-Options、Referrer-Policyなど)と、段階導入が必要なもの(HSTS、CSP)があります。三つ目に、書いただけで終わらせず、実際の応答を見て確認します。
セキュリティヘッダーの種類と推奨値
セキュリティヘッダーは、Webサーバーが返すHTTP応答のヘッダーに含める、ブラウザ向けの安全上の指示です。最初に整えたい6種類を表にします。
| ヘッダー | 役割 | 推奨値の目安 |
|---|---|---|
| Strict-Transport-Security | 以後はHTTPSだけで接続させる | max-age=31536000; includeSubDomains(段階的に導入) |
| Content-Security-Policy | 読み込める取得元を制限する | サイトごとに設計(Report-Onlyから開始) |
| X-Frame-Options | 他サイトのフレーム内表示を禁じる | SAMEORIGIN または DENY |
| X-Content-Type-Options | 内容からの種類の推測を禁じる | nosniff |
| Referrer-Policy | 他サイトへ渡すURL情報を絞る | strict-origin-when-cross-origin |
| Permissions-Policy | カメラや位置情報などの機能を制限する | camera=(), microphone=(), geolocation=() |
注意:HSTSとCSPは、表の値を最初から入れないでください。後半の段階導入の手順で進めます。
Strict-Transport-Security(HSTS)
ブラウザに、そのドメインへは今後HTTPSだけで接続すると、一定期間覚えさせます。max-age は覚えておく秒数で、31536000は1年です。HSTSは、HTTPSの応答に付けたものだけが有効で、HTTPで返したヘッダーはブラウザに無視されます(MDN)。仕様はRFC 6797です。
includeSubDomains を付けると、すべてのサブドメインが対象です。HTTPSに対応していないサブドメインは接続できなくなるため、確認してから付けます。preload は、ブラウザに組み込まれる一覧へ登録する前提の指定で、取り消しに時間がかかります。必要性が明確になるまでは付けません。
Content-Security-Policy(CSP)
読み込んでよいスクリプト、画像、フレームなどの取得元を、サイト側が宣言します。XSSで外部スクリプトが差し込まれても、許可していない取得元のものは実行されないため、被害を小さくできます。一方で、サイトが使う外部サービス(アクセス解析、広告、地図、動画の埋め込みなど)を洗い出す必要があり、6種類のうち最も導入に手間がかかります。詳しくはCSPの用語解説と、後半の段階導入で扱います。
X-Frame-Options
他のサイトが、自サイトを <iframe> の中に表示することを禁じ、クリックジャッキングを防ぎます。値は、どこからの埋め込みも禁じる DENY と、同じオリジンだけ許す SAMEORIGIN です。ALLOW-FROM は現在のブラウザが無視するため、使えません。
新しい方式は、CSPの frame-ancestors です。古いブラウザも考えて、両方を併記しても構いません。frame-ancestors は、metaタグでは効かず、HTTPヘッダーで送る必要があります。用語解説もあります。
X-Content-Type-Options
値は nosniff だけです。ブラウザがファイルの内容から種類を推測し(スニッフィング)、画像として置いたファイルをスクリプトとして実行する、といった挙動を止めます。Content-Type が正しく返っていることが前提です。用語解説
Referrer-Policy
他のサイトへ移動するとき、元のページのURLをどこまで伝えるかを決めます。指定がない場合、近年のブラウザは strict-origin-when-cross-origin を既定にしますが、ブラウザによる差をなくすため、明示します。URLに会員番号などを載せているサイトでは、no-referrer や same-origin も検討します。用語解説
Permissions-Policy
カメラ、マイク、位置情報など、ブラウザの機能を使えるページや埋め込み先を絞ります。サイトが使わない機能は、空の許可リスト () で無効にします。以前の Feature-Policy の後継で、書き方が違います。用語解説
付けなくてよいヘッダーと、消したいヘッダー
X-XSS-Protection は、現在のブラウザでは役割を終えています。OWASPのチートシートは、付けないか、付けるなら 0 にするよう勧めています。ServerやX-Powered-Byに、ApacheやPHPの版が出ている場合は、取り除きます。攻撃者に手がかりを与えないための処置で、脆弱性そのものを直すものではありません。
設定コード:Apache・nginx・WordPress
HTTPSで配信しているサイトの設定例です。HSTSの期間は、最初は300秒にしてあります。段階導入の手順に沿って延ばしてください。
Apache(.htaccess)
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=300"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Header always unset X-Powered-By
</IfModule>
mod_headersが有効なサーバーで動きます。無効だと、<IfModule> の中身は黙って無視されます。always は、404や500などのエラー応答にもヘッダーを付ける指定です。付けないと、成功した応答だけが対象です(mod_headersの公式文書)。Serverヘッダーの版表記を減らす ServerTokens Prod は、サーバー全体の設定で、.htaccessでは指定できません。
nginx
server_tokens off;
add_header Strict-Transport-Security "max-age=300" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
HTTPSの server ブロックに書きます。変更後は nginx -t で構文を確認してから、reloadします。always がないと、200や301などの応答にしか付かず、404や500には付きません(nginxの公式文書)。location の中に別の add_header がある場合の落とし穴は、後半で説明します。
WordPress
WordPressの公式フィルター wp_headers で、WordPressが返す応答にヘッダーを足せます。子テーマの functions.php か、小さな専用プラグインに書きます。親テーマに書くと、テーマの更新で消えます。
add_filter( 'wp_headers', function ( $headers ) {
$headers['X-Content-Type-Options'] = 'nosniff';
$headers['X-Frame-Options'] = 'SAMEORIGIN';
$headers['Referrer-Policy'] = 'strict-origin-when-cross-origin';
$headers['Permissions-Policy'] = 'camera=(), microphone=(), geolocation=()';
return $headers;
} );
注意:この方法で付くのは、WordPressが生成するページの応答だけです。画像やCSSなどの静的ファイルは、WordPressを通らないため対象になりません。サイト全体に付けたい場合や、HSTSを付ける場合は、前述のサーバー設定で行います。
HSTSとCSPの段階導入
HSTSは期間を少しずつ延ばす
- 全ページと、使っているすべてのサブドメインが、HTTPSで表示されることを確認します。
max-age=300(5分)で配信し、全ページで表示や証明書の警告に問題がないか確かめます。max-age=604800(1週間)、max-age=2592000(1か月)と延ばします。前の期間が過ぎるのを待ってから、次へ進みます。- 問題がなければ
max-age=31536000(1年)にします。全サブドメインがHTTPSだと確認できた場合に限り、includeSubDomainsを足します。
この手順は、hstspreload.orgの推奨に沿っています。
CSPはReport-Onlyから始める
最初は、ブロックせず違反だけを報告する Content-Security-Policy-Report-Only で配信します。
Header always set Content-Security-Policy-Report-Only "default-src 'self'; img-src 'self' data: https:; base-uri 'self'; form-action 'self'"
- ページを巡回し、開発者ツールのConsoleに出る
[Report Only]の違反表示を集めます。 - アクセス解析、フォント、地図、動画、問い合わせフォームなど、正当な取得元を許可リストに足します。
- 違反が出なくなったら、ヘッダー名を
Content-Security-Policyに変えて、強制に切り替えます。 - インラインのスクリプトが多い場合は、外部ファイルへ移すか、nonceやハッシュで許可します。
'unsafe-inline'はXSS対策の効果を大きく損なうため、避けられるなら避けます。
違反の報告をサーバーに集めたい場合は、report-to と Reporting-Endpoints ヘッダーを使います。設定例はMDNにあります。
よくある失敗と落とし穴
- always の付け忘れ。付けないと、404や500のエラーページにヘッダーが出ません。表示崩れの確認も、エラーページまで行います。
- nginxのadd_headerの継承。下位の
locationにadd_headerが1つでもあると、上位の指定は全て外れます。nginx 1.29.3以降はadd_header_inherit merge;で足し合わせられます。
server {
add_header X-Content-Type-Options "nosniff" always;
location /assets/ {
add_header Cache-Control "public, max-age=2592000";
}
}
- ヘッダーの二重化。アプリとサーバーの両方が同じヘッダーを返したり、Apacheで
Header addを使ったりすると、同名のヘッダーが2つ並びます。ブラウザの解釈が割れるため、setで上書きします。 - CSPで外部サービスが止まる。アクセス解析、広告、チャット、問い合わせフォームが動かなくなることがあります。Report-Onlyの期間で洗い出します。
- HSTSで、証明書の更新漏れが致命傷になる。HSTSが有効だと、証明書エラーの警告を、利用者は回避して進めません。更新の自動化と期限の監視を先に整えます。
- CDNやキャッシュによる上書き。サーバーでは正しく設定していても、CDNが除去や上書きをすることがあります。確認は、外から実際の応答で行います。
- metaタグでは効かない。X-Frame-Optionsと
frame-ancestorsは、HTMLのmetaタグに書いても無効です。HTTPヘッダーで送ります。
設定できたかを確認する方法
設定ファイルに書いただけでは、付いたかどうかは分かりません。外から実際の応答を見ます。
curlで確認する
curl -I https://example.com/
curl -s -D - -o /dev/null https://example.com/
1行目はHEADリクエストで、ヘッダーだけを取得します。2行目はGETの応答ヘッダーを表示します。HEADに別の応答を返すサーバーでは、2行目のほうが実際の配信に近い結果になります。存在しないURLにも同じ確認をして、404の応答にヘッダーが付いているかも見ます。
ブラウザの開発者ツールで確認する
ChromeやEdgeでは、F12キーで開発者ツールを開き、Networkタブでページを再読み込みします。一覧の先頭にある文書の行を選び、HeadersのResponse Headersを見ます。CSPの違反は、Consoleタブに出ます。
一括して確かめたい場合は、Security Checker XにURLを入力すると、ここで扱ったヘッダーの有無と値、Cookie、証明書までを診断できます。登録は不要です。
よくある質問
セキュリティヘッダーは、検索順位に影響しますか?
これらのヘッダーが検索順位の要因だと、公式に示された事実はありません。一方で、設定を誤って表示や機能が壊れれば、利用者の離脱につながります。段階導入と確認が大切です。
.htaccessに書いたのに、反映されません。何を確認すればよいですか?
次の順に確認します。サーバーがApacheか(nginxは.htaccessを読みません)、mod_headersが有効か、サーバー側で.htaccessの上書きが許可されているか、CDNやキャッシュが古い応答を返していないか。WordPressの場合は、WordPressが書き換える範囲の外に書いているかも見ます。
nginxでserverブロックに書いたのに、一部のURLだけ付きません。
そのURLに当たるlocationブロックの中に、別のadd_headerがある可能性が高いです。add_headerは、下位のブロックに1つでもあると、上位の指定を引き継ぎません。下位のブロックにも同じ指定を書くか、nginx 1.29.3以降のadd_header_inheritを使います。
X-Frame-OptionsとCSPのframe-ancestorsは、どちらを使えばよいですか?
新しい方式はframe-ancestorsです。古いブラウザも考えて、X-Frame-Optionsを併記しても構いません。どちらも、metaタグでは効かず、HTTPヘッダーで送る必要があります。
HSTSをやめて、HTTPに戻したいときはどうしますか?
HTTPSの応答で、max-age=0を返します。ブラウザは、次にHTTPSで接続したときに記憶を消します。ヘッダーを外すだけでは、記憶が期限まで残ります。preloadの一覧に登録済みの場合は、別途削除の手続きが必要で、反映に数か月かかることがあります。
レンタルサーバーでも設定できますか?
多くの場合、できます。.htaccessが使える環境ならApacheの例をそのまま使えます。管理画面にヘッダーの設定欄がある場合や、CloudflareなどのCDNでレスポンスヘッダーを追加できる場合もあります。
まとめ
最初に、X-Content-Type-Options、X-Frame-Options、Referrer-Policy、Permissions-Policyの4つを入れます。HSTSは短い期間から延ばし、CSPはReport-Onlyで影響を見てから強制に切り替えます。どの段階でも、設定後は実際の応答で確かめてください。確認項目の全体像は、Webサイトのセキュリティチェック項目一覧にまとめています。
運用中のサイトへの導入では、影響範囲の見極めが難しいことがあります。設定の代行や、導入後の保守は、ホームページの制作・保守のご相談からお問い合わせください。
よくある質問
セキュリティヘッダーは、検索順位に影響しますか?
これらのヘッダーが検索順位の要因だと、公式に示された事実はありません。一方で、設定を誤って表示や機能が壊れれば、利用者の離脱につながります。段階導入と確認が大切です。
.htaccessに書いたのに、反映されません。何を確認すればよいですか?
次の順に確認します。サーバーがApacheか(nginxは.htaccessを読みません)、mod_headersが有効か、サーバー側で.htaccessの上書きが許可されているか、CDNやキャッシュが古い応答を返していないか。WordPressの場合は、WordPressが書き換える範囲の外に書いているかも見ます。
nginxでserverブロックに書いたのに、一部のURLだけ付きません。
そのURLに当たるlocationブロックの中に、別のadd_headerがある可能性が高いです。add_headerは、下位のブロックに1つでもあると、上位の指定を引き継ぎません。下位のブロックにも同じ指定を書くか、nginx 1.29.3以降のadd_header_inheritを使います。
X-Frame-OptionsとCSPのframe-ancestorsは、どちらを使えばよいですか?
新しい方式はframe-ancestorsです。古いブラウザも考えて、X-Frame-Optionsを併記しても構いません。どちらも、metaタグでは効かず、HTTPヘッダーで送る必要があります。
HSTSをやめて、HTTPに戻したいときはどうしますか?
HTTPSの応答で、max-age=0を返します。ブラウザは、次にHTTPSで接続したときに記憶を消します。ヘッダーを外すだけでは、記憶が期限まで残ります。preloadの一覧に登録済みの場合は、別途削除の手続きが必要で、反映に数か月かかることがあります。
レンタルサーバーでも設定できますか?
多くの場合、できます。.htaccessが使える環境ならApacheの例をそのまま使えます。管理画面にヘッダーの設定欄がある場合や、CloudflareなどのCDNでレスポンスヘッダーを追加できる場合もあります。
関連記事
- Webサイトのセキュリティチェック項目30選|確認方法つき一覧表
- WordPressの脆弱性を確認する方法|本体・プラグインの更新と対処の手順
- SSL/TLS証明書のチェック方法|有効期限・チェーン・通信方式の確認手順
関連する用語
- セキュリティヘッダー
- HSTS
- CSP
- X-Frame-Options
- X-Content-Type-Options
- Referrer-Policy
- Permissions-Policy
- クリックジャッキング
- XSS
サイトの設定を無料で確認する
この記事の内容を、自分のサイトで確かめたい時は、Webサイト セキュリティチェッカー「Security Checker X」をお使いください。URLを入力するだけで、登録なしで診断できます。










コメント