この記事の結論
セキュリティヘッダーは、1つのヘッダーを1か所(原則はWebサーバー)だけで付けるのが基本です。X-Content-Type-Options、Referrer-Policy、X-Frame-Options、Permissions-Policyの4つは、確認後すぐに入れられます。HSTSはmax-age=300から段階的に延ばし、CSPはReport-Onlyで違反を集めてから強制に切り替えます。設定後は curl -I で、トップページ、存在しないURL、リダイレクトの応答に、各ヘッダーが1本ずつ付いているかを確かめてください。
セキュリティヘッダーは影響の小さい順に4段階で入れる
最初に入れるのは、表示が壊れにくいX-Content-Type-OptionsとReferrer-Policyです。次にX-Frame-OptionsとPermissions-Policy、3段階目にHSTS、最後にCSPを入れます。段階を分けておくと、表示や機能が壊れたときに原因のヘッダーを1つに絞り込めます。
| 段階 | ヘッダー | 推奨値 | 入れる前に確かめること |
|---|---|---|---|
| 1 | X-Content-Type-Options | nosniff | JavaScriptとCSSが正しいContent-Typeで返っているか |
| 1 | Referrer-Policy | strict-origin-when-cross-origin | 外部サービスにURLのパスまで渡す連携がないか |
| 2 | X-Frame-Options | SAMEORIGIN | 他サイトの枠(iframe)に自サイトを表示させていないか |
| 2 | Permissions-Policy | camera=(), microphone=(), geolocation=() | カメラ、マイク、位置情報を使う画面がないか |
| 3 | Strict-Transport-Security | max-age=300から延ばし、最終は1年以上 | 全ページとサブドメインがHTTPSか、証明書の更新が自動か |
| 4 | Content-Security-Policy | Report-Onlyから始め、値はサイトごとに設計 | 外部のタグ、埋め込み、インラインスクリプトの一覧 |
セキュリティヘッダーの推奨値は、OWASPのHTTP Headers Cheat Sheetを基準にし、X-Frame-Optionsだけは自サイト内の枠表示を残せる SAMEORIGIN にしています(OWASPは DENY)。段階1と同時に、ServerヘッダーとX-Powered-Byに出る版の表記も消します。
ポイント
各段階の後で、問い合わせフォーム、決済、地図、動画、アクセス解析など、外部と連携する画面を動かしてから次へ進みます。
ヘッダーはどこで付き、ブラウザはどう使うか
セキュリティヘッダーは、アプリ(WordPressなど)、Webサーバー、CDNのどこでも付けられ、ブラウザは手元に届いた応答のヘッダーに従って動作を変えます。ブラウザからは、どこで付いたヘッダーかを区別できません。1つのヘッダーを付ける場所を1か所に決めることが、重複と付け漏れを防ぐ近道です。
| 付ける場所 | ヘッダーが付く応答 | 向いている場面 | 注意点 |
|---|---|---|---|
| Webサーバー(Apache、nginx) | 静的ファイル、エラー、リダイレクトを含む全応答(alwaysを付けた場合) | 基本の置き場所 | アプリが同じヘッダーを出すと2本並ぶ |
| CDN(Cloudflareなど) | CDNを通る全応答 | サーバーの設定を変えられないとき | 「追加」の操作は既存の同名ヘッダーを残す |
| アプリ(WordPressなど) | アプリが生成したページだけ | 応答ごとに値が変わるCSPのnonce | 画像、CSS、サーバー側のリダイレクトには付かない |
ポイント
原則はWebサーバーで付け、CSPのnonceのように応答ごとに値を作るものだけをアプリで付けます。CDNは、サーバーの設定を変えられないときの代わりです。どのヘッダーをどこで付けたかは、一覧にして残します。
各ヘッダーの設定値と推奨値
段階1と2の4つは推奨値がほぼ決まっており、自サイトの使い方と突き合わせれば決められます。HSTSとCSPは、後の節の手順で扱います。
X-Content-Type-Options: nosniff
X-Content-Type-Optionsの値は nosniff だけで、Content-TypeがJavaScriptの種類でないスクリプトと、text/cssでないスタイルシートを読み込ませなくします。Chrome 146の場合、text/plainで返したJavaScriptは、nosniffが無いと実行され、付けると止まります。
入れる前に curl -sI https://example.com/main.js で、主なJavaScriptのContent-Typeを調べます。text/javascript などなら合格で、text/plain などならサーバーのMIMEタイプの設定を先に直します。
Referrer-Policy: strict-origin-when-cross-origin
Referrer-Policyは、リンク先や外部の読み込み先へ、元のページのURLをどこまで伝えるかを決めます。推奨値は、同じオリジンにはURL全体を、別のオリジンには https://example.com/ のようなオリジンだけを伝え、HTTPSからHTTPへは何も送りません。指定が無いときの既定値でもありますが、OWASPは明示するよう勧めています。
URLに会員番号などを含むサイトでは、no-referrer や same-origin も選べます。ただし、Google Maps Platformの公式文書によると、この2つではRefererが送られず、Refererで制限したAPIキーが要求を拒否する場合があります。
X-Frame-Options と frame-ancestors の関係
X-Frame-Optionsは、自サイトのページを他サイトの枠(iframe)の中に表示させない指示で、クリックジャッキングを防ぎます。値は、すべての枠を拒否する DENY と、すべての親が同じオリジンのときだけ許す SAMEORIGIN の2つです。特定のサイトを許す ALLOW-FROM は廃止され、現在のブラウザはこの値を含むヘッダー全体を無視します。
特定のサイトにだけ埋め込みを許す方法は、CSPの frame-ancestors 'self' https://partner.example.jp のような指定です。CSPの仕様(W3C CSP Level 3)は、強制モードのCSPに frame-ancestors があれば、X-Frame-Optionsを無視すると定めています。Chrome 146でも、X-Frame-Options: DENY より frame-ancestors の許可が優先されます。
新旧のブラウザに対応するため、2つは併記できます。WordPressは管理画面やカスタマイザーで自サイトを枠の中に表示し、本体も SAMEORIGIN を付けるため、サーバー側もSAMEORIGINにそろえます。
Permissions-Policy
Permissions-Policyは、カメラ、マイク、位置情報などのブラウザ機能を、そのページと埋め込んだiframeで使えるかを決めます。値は機能ごとに、() で全面禁止、(self) で自サイトだけ、(self "https://map.example.jp") で指定のオリジンにも許可します。旧仕様のFeature-Policyの camera 'none' は、camera=() と書き換えます。
止めるのは、使っていない機能だけです。店舗検索で位置情報を使うなら geolocation=(self) にし、決済でPayment Request APIを使うなら payment は止めません。
付けないヘッダーと、消すヘッダー
X-XSS-Protectionは廃止されたヘッダーで、OWASPは付けないか、付けるなら 0 にするよう勧めています。古いブラウザのXSS検出機能が、安全なサイトにかえってXSSの弱点を生む場合があったためです。ChromiumがVersion 107で廃止したExpect-CTも、付ける必要はありません。
ServerとX-Powered-Byに出る版の表記は、Apacheならhttpd.confの ServerTokens Prod(.htaccessでは不可)で消します。nginxは server_tokens off;、PHPはphp.iniの expose_php = Off です。版を隠すだけでは安全にならないとApacheの公式文書も述べており、WordPressの本体とプラグインの更新のような更新作業を優先します。
Apache、nginx、WordPress、Cloudflareの設定例
段階1と2の4つのヘッダーに、HSTSの最初の値(max-age=300)を加えた設定例です。どの環境でも、404などのエラー応答とリダイレクトにもヘッダーが付く書き方を選ぶことが要点です。
Apache(.htaccess、VirtualHost)
# .htaccess、またはHTTPSのVirtualHostに書く
<IfModule mod_headers.c>
# アプリが同名のヘッダーを出しても1本になるよう、unsetとalways setを対にする
Header unset X-Content-Type-Options
Header always set X-Content-Type-Options "nosniff"
Header unset Referrer-Policy
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header unset X-Frame-Options
Header always set X-Frame-Options "SAMEORIGIN"
Header unset Permissions-Policy
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Header unset Strict-Transport-Security
Header always set Strict-Transport-Security "max-age=300"
# PHPの版の表記を消す(PHPの動かし方で入る表が違うため2行とも書く)
Header unset X-Powered-By
Header always unset X-Powered-By
</IfModule>
Apacheの Header には、既定の「onsuccess」と「always」の2つの表があります。Apacheが自ら作る404やリダイレクト(RedirectやRewriteRuleの301)では、always の表しか使われず、always の無い指定は付きません(mod_headersの公式文書)。
PHPのヘッダーが入る表は動かし方で違い、mod_phpでは既定の表に、CGIやFastCGI(PHP-FPMなど)では always の表に入ります。Header always set だけではmod_phpでアプリの同名ヘッダーと2本並ぶため、例のように Header unset と対で書くと、どちらの方式でも1本になります。LiteSpeedなどApache互換のサーバーでは扱いが異なる場合があるため、設定後にcurlで本数を確かめます。
.htaccessの指定は、そのフォルダに届いた要求にだけ効き、VirtualHostやコントロールパネルで行うリダイレクトには付きません。HSTSは、変更できるならVirtualHostに書くのが確実です。mod_headersが無効な場合、<IfModule> で囲んだ指定は黙って無視され、囲まない指定は500エラーになります。
nginx
# /etc/nginx/snippets/security-headers.conf(共通の指定を1か所にまとめる)
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Strict-Transport-Security "max-age=300" always;
# HTTPSのserverブロック(証明書などの設定は省略)
server {
listen 443 ssl;
server_name example.com;
server_tokens off;
include snippets/security-headers.conf;
location /assets/ {
add_header Cache-Control "public, max-age=2592000";
# add_headerを書いた場所では上の指定が消えるため、読み込み直す
include snippets/security-headers.conf;
}
}
nginxの add_header は、always が無いと200や301などの決まった応答にしか付かず、404や500には付きません(nginxの公式文書)。また、下の階層に add_header が1つでもあると、上の階層の add_header はすべて引き継がれません。例の /assets/ のように、キャッシュ用のヘッダーを足したlocationでセキュリティヘッダーが消えるのは、このためです。
対策は、共通のファイルを各locationで読み込み直すか、nginx 1.29.3以降(安定版は1.30.0以降)の add_header_inherit merge; をserverブロックに書く方法です。OSの標準パッケージは版が古いことがあるため、nginx -v で確かめてから選びます。アプリが出した同名のヘッダーは置き換わらずに残るので、PHP-FPMなら fastcgi_hide_header X-Frame-Options; のように隠します(リバースプロキシは proxy_hide_header)。
WordPress
サーバーの設定を変えられない場合は、WordPressの wp_headers フィルターで足せます。コードを wp-content/mu-plugins/ の直下に置くと自動で読み込まれ、テーマの変更でも消えず、管理画面から無効にもできません。
<?php
// wp-content/mu-plugins/security-headers.php として保存する
add_filter( 'wp_headers', function ( $headers ) {
$headers['X-Content-Type-Options'] = 'nosniff';
$headers['Referrer-Policy'] = 'strict-origin-when-cross-origin';
$headers['X-Frame-Options'] = 'SAMEORIGIN';
$headers['Permissions-Policy'] = 'camera=(), microphone=(), geolocation=()';
return $headers;
} );
このフィルターは、公式リファレンスにあるとおりWP::send_headers()の中で適用され、効くのは公開ページの応答だけです。管理画面、ログイン画面、REST API、画像やCSSには付かないため、HSTSはサーバーかCDNで付けます。
WordPress 6.9以降は、管理画面とログイン画面に、本体が X-Frame-Options: SAMEORIGIN と frame-ancestors 'self' のCSPを付けます。サーバー側でCSPを付けるときは、この2つの画面でも値が食い違わないかの確認が必要です。
Cloudflare
Cloudflareでは、Rules Overviewの「Create rule」から「Response Header Transform Rule」を作ります。操作は、同名のヘッダーを上書きする「Set static」を選びます。「Add」は既存のヘッダーを残したまま足すため、オリジンの値と2本並びます。
HSTSは、Edge Certificatesの画面にある専用の設定で付けられます。マネージド変換の「Add security headers」は、OWASPが勧めない X-XSS-Protection: 1; mode=block や廃止済みのExpect-CTも付けるため、個別のルールで付ける方が推奨値にそろえやすくなります。
HSTSの設定方法と、max-ageを延ばす手順
HSTSは、HTTPSがサイト全体で安定してから、max-ageを5分、1週間、1か月と延ばし、最後に1年以上にします。HSTSを覚えたブラウザでは、証明書の期限切れなどのエラーのとき、利用者が警告を越えて進めなくなります。そのため、証明書の更新の自動化を先に済ませます。
HSTSを受け取ったブラウザは、受け取った時点からmax-ageの秒数だけそのホストを覚え、HTTPのURLもHTTPSに切り替えて接続します(RFC 6797)。HTTPの応答に付けたHSTSは無視されるため、HTTPSの応答に付けます。
- 前提をそろえる全ページがHTTPSで表示され、混在コンテンツが無く、HTTPからHTTPSへ301で転送していることを確かめます。証明書の自動更新と期限の監視も整えます。期限の確かめ方は、SSL/TLS証明書のチェック方法で説明しています。
- サブドメインを含めるか決めるincludeSubDomainsは、社内向けを含むすべてのサブドメインがHTTPSで動く場合だけ付けます。付けるなら、登録窓口のhstspreload.orgが勧める手順のとおり、最初の5分の段階から付けて試します。
- max-age=300で配信する全ページと各サブドメインを開き、問い合わせ、決済、ログインまで動かします。
- 1週間、1か月と延ばす604800、2592000の順に延ばします。各段階では、その値の期間が過ぎるまで待ってから次へ進みます。
- 1年以上にする最終値は31536000(1年)以上にします。OWASPとhstspreload.orgの例は63072000(2年)です。
# 段階ごとの値(includeSubDomainsは、付けると決めた場合だけ)
Strict-Transport-Security: max-age=300; includeSubDomains
Strict-Transport-Security: max-age=604800; includeSubDomains
Strict-Transport-Security: max-age=2592000; includeSubDomains
Strict-Transport-Security: max-age=31536000; includeSubDomains
注意
preloadは付けません。hstspreload.org自身が『HSTSは推奨するが、HSTS preloadは推奨しない』と明記しています。ChromeやSafariはHSTSが無くてもHTTPの移動をHTTPSへ切り替えるため、preloadの上乗せの効果は小さいという説明です。
preloadを付けたヘッダーは、一覧への登録を求めているとみなされます。登録後の削除は、Chromeの更新で利用者に届くまで数か月かかり、他のブラウザでの反映は保証されません。
CSPの設定例と、Report-Onlyからの段階導入
CSPは、まずContent-Security-Policy-Report-Onlyという名前で配信して違反を集め、正当な取得元を許可リストに足します。違反が出なくなったら、ヘッダー名をContent-Security-Policyに変えて強制します。Report-Onlyは読み込みを何も止めないので、本番のサイトで影響だけを測れるのが利点です。
- Report-Onlyで配信する最初は、自サイト以外の取得元を違反として記録するだけの方針にします(下の設定例)。
- 全ページを巡回して違反を集めるトップ、記事、フォーム、決済、管理画面まで開き、Consoleの違反を記録します。
- 許可リストを直すアクセス解析、フォント、地図、動画などの取得元を、必要なディレクティブにだけ足します。
- ヘッダー名を変えて強制する違反が出なくなったら、Content-Security-Policyに切り替えます。さらに厳しくする案は、Report-Onlyで同時に送って試せます。
- nonceかハッシュで厳しくするインラインスクリプトを許す
'unsafe-inline'を外し、web.devが勧める厳格なCSPへ近づけます。
# Apache(行末の\は次の行へ続く印。\の後ろに空白を入れない)
Header always set Content-Security-Policy-Report-Only "default-src 'self'; \
img-src 'self' data: https:; object-src 'none'; base-uri 'self'; \
form-action 'self'; frame-ancestors 'self'"
# nginx(serverブロックに書く。長い値は変数に分けて組み立てる)
set $csp "default-src 'self'; img-src 'self' data: https:; ";
set $csp "${csp}object-src 'none'; base-uri 'self'; ";
set $csp "${csp}form-action 'self'; frame-ancestors 'self'";
add_header Content-Security-Policy-Report-Only $csp always;
default-srcが代わりを務めるのは、script-srcやimg-srcなどの取得系の指定だけです。base-uri、form-action、frame-ancestorsは個別に書きます。object-src 'none' はプラグインによる埋め込みを止める指定で、web.devの推奨にも含まれる値です。
Chrome 146では、違反はConsoleに情報(Info)として表示され、末尾に『The policy is report-only』で始まる一文が付きます。強制に切り替えると同じ違反がエラーになり、末尾は『The action has been blocked.』に変わります。インラインスクリプトの違反に示される『sha256-…』の値をscript-srcに足すと、そのスクリプトだけを許可できます。
違反をサーバーに集めるには、受け口を Reporting-Endpoints ヘッダーで示し、ポリシーに report-to を足します。設定例はMDNのContent-Security-Policy-Report-Onlyにあり、古いブラウザ向けに report-uri も併記しています。受け口には、ブラウザが送るJSONを保存する仕組みが別に要ります。
強制に切り替えた後は、web.devが勧める厳格なCSPへ近づけます。web.devは、ドメインを並べる許可リスト方式は多くの構成で回避されうるとし、nonce(応答ごとの乱数)かハッシュで許可する方式を勧めています。nonceは暗号学的に安全な乱数(128ビット以上が望ましい)で、応答のたびに作り直します。
# web.devが勧める厳格なCSP({RANDOM}は応答ごとに作る乱数)
Content-Security-Policy: script-src 'nonce-{RANDOM}' 'strict-dynamic';
object-src 'none'; base-uri 'none';
# HTML側は、許可するscriptタグに同じ値を付ける
<script nonce="{RANDOM}" src="/js/app.js"></script>
注意
script-srcに 'unsafe-inline' を残すと、差し込まれたインラインスクリプトも実行できるため、XSSへの効果は大きく下がります。WordPressのように本体やプラグインがインラインスクリプトを出すサイトでは、最初は残すしかない場合もあります。その場合でも、frame-ancestors、form-action、base-uri、object-srcの制限は働きます。
同じヘッダーが2本届いたときに起きること
同名のヘッダーが2本届いたときの扱いはヘッダーごとに違い、HSTSは最初の1本だけ、CSPは両方が効いて厳しい側が勝ちます。X-Frame-Optionsは値が食い違うと、同じサイトの枠の中でも表示を拒否します。重複はエラーにならず黙って起きるため、確認の段階で本数を数えます。
| ヘッダー | 2本届いたときの扱い | 根拠 |
|---|---|---|
| Strict-Transport-Security | 最初の1本だけを処理する | RFC 6797 |
| Content-Security-Policy | 両方を適用し、より厳しい制限が効く | MDN、Chrome 146の動作 |
| X-Frame-Options | 同じ値なら1本と同じ。DENYとSAMEORIGINが並ぶと、すべての枠で拒否 | Chrome 146の動作 |
| Referrer-Policy | カンマで並んだ値のうち、最後の有効な値を使う | MDN、Chrome 146の動作 |
| Permissions-Policy | 同じ機能の指定は、後に届いた方が有効 | Chrome 146の動作 |
根拠をChrome 146の動作とした行は、他のブラウザで扱いが異なる場合があります。重複を残さないことが、どのブラウザでも確実な対策です。
X-Frame-Optionsの値が食い違うと、Chrome 146はConsoleに次の例のように表示し、DENYとして扱います。
Refused to display 'https://example.com/' in a frame because it set multiple
'X-Frame-Options' headers with conflicting values ('DENY, SAMEORIGIN').
Falling back to 'deny'.
主な原因は、アプリとサーバーによる二重の付与と、Apacheの Header add やCloudflareの「Add」のような追加の操作です。付ける場所を1つに絞り、操作はsetにそろえます。
設定できたかをcurlと開発者ツールで確かめる
確認は設定ファイルではなく、外から取った実際の応答で行います。トップページ、存在しないURL、HTTPSのリダイレクト、画像やCSS、ログイン画面の5種類で、各ヘッダーが1本ずつ付いていれば合格です。
# ヘッダーだけを取得する(-IはHEADリクエスト)
curl -sI https://www.example.com/
# GETで取得し、応答ヘッダーだけを表示する
curl -s -D - -o /dev/null https://www.example.com/
# 404の応答にも付いているか
curl -sI https://www.example.com/no-such-page/
# wwwへ転送するリダイレクトに、HSTSが付いているか
curl -sI https://example.com/ | grep -i -E '^(HTTP|location|strict-transport)'
# 重複していないか(1なら合格)
curl -sI https://www.example.com/ | grep -ci '^x-frame-options:'
# Windows PowerShell 5.1は curl.exe と書き、findstrで絞る
curl.exe -sI https://www.example.com/ | findstr /i "x-frame-options"
Windows PowerShell 5.1では curl がInvoke-WebRequestの別名のため、.exe まで書きます。HEADとGETで違う応答を返すサーバーもあるので、GETの結果も見ておくと確実です。
- トップページ(200)に、入れたヘッダーがそれぞれ1本ずつ付いている
- 存在しないURL(404)にも、同じヘッダーが付いている
- wwwの有無をそろえる転送など、HTTPSのリダイレクトにHSTSが付いている
- 画像、CSS、JavaScriptにも付き、Content-Typeが種類どおりになっている
- ログイン画面や管理画面で、X-Frame-OptionsやCSPの値が食い違っていない
ブラウザでは、F12キーで開発者ツールを開き、Network(ネットワーク)タブで再読み込みします。先頭の文書を選んでHeaders(ヘッダー)のResponse Headers(レスポンス ヘッダー)を見て、CSPの違反はConsole(コンソール)タブで確かめます。
主なヘッダーをまとめて確かめるには、無料のWebサイトのセキュリティチェックも使えます。URLを入れると、HSTSの有無と有効期間、サブドメインへの適用、CSP、X-Frame-Optionsなど6種類のヘッダーを確認し、AからFの判定と直し方を表示します。ヘッダー以外の確認項目は、Webサイトのセキュリティチェック項目の一覧にまとめています。
表示や機能が壊れたときの戻し方
CSP、X-Frame-Options、Permissions-Policyは、設定を戻せば次の読み込みから元に戻ります。HSTSだけは、ブラウザが覚えた期間が残るため、すぐには戻せません。
| ヘッダー | 主な症状 | 戻し方 |
|---|---|---|
| Content-Security-Policy | アクセス解析、地図、フォームが動かない | ヘッダー名をReport-Onlyに戻し、許可リストを直す |
| X-Frame-Options、frame-ancestors | 提携先の枠の中やプレビューが表示されない | 許す親のオリジンだけをframe-ancestorsに足す |
| Permissions-Policy | 位置情報やカメラが動かない(Consoleに『Permissions policy violation』) | その機能を (self) などの許可に変える |
| X-Content-Type-Options | JavaScriptやCSSが読み込まれない(Consoleに『strict MIME type checking is enabled』) | nosniffは外さず、Content-Typeを直す |
| Strict-Transport-Security | 証明書のエラーで、利用者がページに進めない | 証明書を直す(下の注意を参照) |
注意
HSTSを外すだけでは、ブラウザの記憶は期限まで残ります。HTTPSの応答で max-age=0 を返すと、そのブラウザが次にHTTPSで接続したときに記憶が消えますが、HTTPでは消せず、再訪しない利用者には届きません。CloudflareのHSTSも同じで、HSTSを無効にして元のmax-ageの期間が過ぎる前にHTTPSをやめると、サイトに接続できなくなると公式文書が警告しています。
補足
試験で自分のChromeに残った記憶は、chrome://net-internals/#hsts の「Delete domain security policies」にドメインを入れて消せます。消せるのはそのブラウザの記憶だけで、プリロード済みの登録は消せません。CDNやページキャッシュが応答を保存している場合は、キャッシュを消すまで古いヘッダーが届きます。
ヘッダーの設定を1つのファイルにまとめて変更の履歴を残すと、1行の変更で戻せます。影響範囲を見極めにくい場合や、原因のヘッダーを切り分けられない場合は、診断や設定についての相談窓口からお問い合わせください。
よくある質問
セキュリティヘッダーは検索順位に影響しますか?
順位への影響を示すGoogleの公式な説明は見当たりません。Googleの検索セントラルは、ページエクスペリエンスの確認項目にHTTPSを挙げていますが、個々のセキュリティヘッダーには触れていません(2026年10月時点)。一方、CSPの誤設定で問い合わせフォームや計測タグが止まると、成果に直接響きます。
.htaccessに書いたのに反映されません。どこを確かめればよいですか?
サーバーの種類、上書きの許可、モジュール、キャッシュの順に確かめます。nginxは.htaccessを読まず、ApacheでもHeaderの指定には、AllowOverride FileInfo の許可とmod_headersの有効化が必要です。設定が正しいのに付かないときは、CDNやページキャッシュを消してから curl で確かめます。
metaタグでセキュリティヘッダーを設定できますか?
一部だけできます。CSPは <meta http-equiv="Content-Security-Policy"> で設定できますが、frame-ancestors、report-uri、sandboxは効かず、metaより前にある内容にも適用されません。Referrer-Policyは <meta name="referrer"> で指定でき、HSTS、X-Frame-Options、Content-Security-Policy-Report-Onlyはmetaに書いても無視されます。
WordPressでCSPのnonceは使えますか?
条件付きで使えます。WordPress 5.7以降は、wp_script_attributes と wp_inline_script_attributes のフィルターで、本体の関数が出力するscriptタグにnonce属性を足せます。ただし、HTMLを丸ごと保存するページキャッシュとは両立せず、プラグインが直接書き出すscriptタグにも付かないため、Report-Onlyで漏れを確かめます。
ステージング環境や社内システムのサブドメインにHSTSは影響しますか?
影響するかどうかは、includeSubDomainsをどのホストが返すかで決まります。RFC 6797では、includeSubDomainsは、ヘッダーを返したホストとその下のドメインに効きます。
www.example.jpだけが返すなら、dev.example.jpには効きません。example.jpが返すと、HTTPSに対応していない社内向けのサブドメインも、ブラウザで開けなくなります。
OWASPが挙げるCOOP、COEP、CORPも入れるべきですか?
この記事の6種類を整えてから検討します。OWASPが挙げるCross-Origin-Embedder-Policyの require-corp は、他のオリジンが読み込みを許していない画像や埋め込みを、読み込めなくする指定です。外部サービスを多く使うサイトほど影響が大きいため、1つずつ表示を確かめながら入れます。
Permissions-Policyは、SafariやFirefoxでも効きますか?
2026年10月時点では効きません。MDNの互換性データでは、このヘッダーに対応しているのはChromeやEdgeなどのChromium系で、FirefoxとSafariは未対応です。未対応のブラウザでは指定が無視されるだけなので、対応ブラウザでの補助の対策として入れます。
関連記事
設定したヘッダーを無料で確かめる
URLを入力すると、HSTS、CSP、X-Frame-Optionsなど6種類のヘッダーの有無に加え、証明書やCookieの属性もまとめて確認できます。メールアドレスの登録は要りません。
無料でWebサイトをチェックする









