2026年8月7日
2026年8月7日
HTTPセキュリティヘッダーの設定ガイド(Apache・Nginx・WordPress別)
HTTP セキュリティヘッダーは、ブラウザに「このサイトをどう扱ってよいか」を伝える指示で、クリックジャッキングや MIME タイプの誤判定、意図しない外部スクリプトの読み込みといった攻撃の余地を減らせます。この記事では、WordPress サイトで設定する価値が高い6種類のヘッダーについて、それぞれの意味と推奨値、Apache・Nginx・WordPress(PHP)での書き方、サイトを壊さずに導入する順番、確認方法を説明します。
設定する価値が高いヘッダー
まず全体像です。上から順に、導入しやすく効果が分かりやすいものです。
| ヘッダー | 役割 | 導入の難しさ |
|---|---|---|
| X-Content-Type-Options | ファイルの種類を推測させない | 低い |
| Referrer-Policy | 外部へ送る参照元 URL の範囲を決める | 低い |
| X-Frame-Options / frame-ancestors | 他サイトの iframe への埋め込みを制限する | 低い〜中 |
| Permissions-Policy | カメラや位置情報などの機能の利用を制限する | 中 |
| Strict-Transport-Security(HSTS) | HTTPS での接続を強制する | 中(戻しにくい) |
| Content-Security-Policy(CSP) | 読み込んでよいスクリプトや画像の出どころを決める | 高い |
X-Content-Type-Options
X-Content-Type-Options: nosniff
ブラウザが Content-Type を無視してファイルの中身から種類を推測する動作を止めます。アップロードされた画像に見せかけたファイルがスクリプトとして解釈される、といった事態を防ぐ助けになります。副作用はほとんどありませんが、サーバーが CSS や JavaScript に誤った Content-Type を付けていると読み込まれなくなるため、設定後に表示崩れがないかを見ます。
Referrer-Policy
Referrer-Policy: strict-origin-when-cross-origin
他サイトへのリンクをたどったとき、送る参照元をドメインまでに抑えます。URL にトークンや検索語が含まれる場合の漏えいを減らせます。現在の主要ブラウザの既定値もこの値ですが、明示しておくと意図がはっきりします。アクセス解析で参照元のページ単位の情報が必要な場合は、影響を確認してから決めます。
X-Frame-Options と CSP の frame-ancestors
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
自サイトのページを他サイトの iframe に埋め込ませないことで、透明な iframe を重ねてクリックさせる「クリックジャッキング」を防ぎます。新しい仕様は CSP の frame-ancestors で、X-Frame-Options は古いブラウザ向けに併記されることが多いです。WordPress は管理画面とログイン画面ではもともと X-Frame-Options: SAMEORIGIN を送っていますが、公開ページには送りません。
Permissions-Policy
Permissions-Policy: camera=(), microphone=(), geolocation=()
() は「どのオリジンにも許可しない」という意味です。使っていない機能を無効にしておくと、埋め込まれた広告や外部スクリプトがそれらを使うことを防げます。地図や動画、決済などの埋め込みが特定の機能を必要とする場合は、その機能を外すか、許可するオリジンを書きます。
X-XSS-Protection は設定しなくてよい
古い記事では X-XSS-Protection: 1; mode=block が推奨されていることがありますが、この機能を持っていたブラウザ側の仕組みは主要ブラウザから削除されています。現在は設定しないか、0 を指定するのが一般的な推奨です。XSS 対策は CSP と、WordPress 側の出力エスケープで行います。
1. まず現在のヘッダーを確認する
設定を始める前に、今どのヘッダーが送られているかを確認します。サーバー、CDN、セキュリティプラグインのどこかですでに設定されていることがあるためです。
curl -sI https://example.com/ | grep -iE "strict-transport|content-security|x-frame|x-content-type|referrer-policy|permissions-policy"
ブラウザの開発者ツールの「ネットワーク」タブで、ページを選んでレスポンスヘッダーを見る方法でも確認できます。
2. Apache での設定
mod_headers が有効になっている必要があります。バーチャルホストの設定ファイルか、WordPress の .htaccess に書きます。.htaccess に書く場合は、WordPress が管理する # BEGIN WordPress と # END WordPress の外側に置きます。内側に書くとパーマリンク設定の保存で消えることがあります。
<IfModule mod_headers.c>
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
</IfModule>
always を付けると、エラーページやリダイレクトの応答にも付与されます。編集前に設定ファイルをバックアップし、apachectl configtest(環境によっては apache2ctl configtest)で書式を確認してから再読み込みします。
3. Nginx での設定
server {
# ...
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;
}
Nginx でもっともつまずきやすいのは継承の仕様です。location ブロックの中に add_header を1つでも書くと、外側の server ブロックの add_header はその location では一切使われません。画像のキャッシュ設定などで location 内に add_header を書いている場合、その location にはセキュリティヘッダーを書き直す必要があります。共通部分を別ファイルにして include すると管理しやすくなります。
sudo nginx -t && sudo systemctl reload nginx
4. WordPress(PHP)での設定
サーバー設定を触れないレンタルサーバーでは、PHP から送る方法があります。子テーマの functions.php か、mu-plugin として wp-content/mu-plugins/ に置きます。
<?php
// wp-content/mu-plugins/security-headers.php
add_action( 'send_headers', function () {
if ( headers_sent() ) {
return;
}
header( 'X-Content-Type-Options: nosniff' );
header( 'Referrer-Policy: strict-origin-when-cross-origin' );
header( 'X-Frame-Options: SAMEORIGIN' );
header( 'Permissions-Policy: camera=(), microphone=(), geolocation=()' );
} );
send_headers アクションは公開ページのリクエストで実行され、管理画面では実行されません。また、ページキャッシュ系のプラグインやサーバーのキャッシュが静的な HTML を返す場合、PHP を通らないためヘッダーが付かないことがあります。設定後はキャッシュを削除し、curl で確認してください。
同じヘッダーをサーバー設定とプラグインの両方で送ると、重複して2つ送られることがあります。CSP が2つ送られると両方の制限がかかり、X-Frame-Options が重複すると無効と扱われる場合があります。設定する場所は1か所にまとめます。
5. HSTS は短い期間から始める
Strict-Transport-Security: max-age=300
HSTS を受け取ったブラウザは、指定した期間そのドメインに HTTP で接続しなくなります。証明書の更新に失敗したり、HTTPS に対応していないサブドメインがあったりすると、期間が切れるまで利用者がアクセスできません。
最初は max-age=300(5分)のような短い値で試し、問題がなければ1日、1週間と延ばし、最終的に1年(31536000)にします。includeSubDomains は、すべてのサブドメインが HTTPS で動いていることを確認してから付けます。ブラウザに組み込まれる preload リストへの登録は、取り消しに時間がかかるため、条件とリスクを理解したうえで検討してください。HSTS は HTTPS の応答に付けたものだけが有効です。
6. CSP は Report-Only から始める
CSP は効果が大きい一方で、WordPress ではもっとも導入が難しいヘッダーです。テーマやプラグインがインラインのスクリプトやスタイル、外部の CDN、アクセス解析、広告、埋め込み動画などを使っているため、厳しいポリシーをいきなり適用すると機能が止まります。
まずは、壊れにくい指定だけを先に適用する方法があります。
Content-Security-Policy: frame-ancestors 'self'; base-uri 'self'; object-src 'none'
スクリプトの出どころを制限するポリシーは、Report-Only ヘッダーで違反を記録するだけの状態から始めます。
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; img-src 'self' data: https:; style-src 'self' 'unsafe-inline'
ブラウザの開発者ツールのコンソールに違反が表示されるので、正当な読み込み元を1つずつ追加していきます。ブロックエディターなど管理画面の動作に影響しやすいため、最初は公開ページだけに適用するのが無難です。
7. 設定後の確認
- curl で各ヘッダーが1回ずつ送られているかを見る
- トップページ・投稿・固定ページ・お問い合わせフォーム・ログイン画面・管理画面を開き、表示や送信に問題がないか確かめる
- 外部の診断サービス(securityheaders.com や MDN HTTP Observatory など)で抜けを確認する
診断サービスの評価は目安です。点数を上げるために必要のない制限まで加えると、サイトの機能を損ないます。サービスの評価基準や提供状況は変わることがあります(2026年10月現在)。
まとめ
- X-Content-Type-Options・Referrer-Policy・X-Frame-Options は副作用が少なく、最初に設定しやすい
- X-XSS-Protection は設定しないか 0 にする。XSS 対策は CSP と出力エスケープで行う
- Apache は Header always set、Nginx は add_header ... always。Nginx は location 内の add_header で継承が切れる点に注意
- PHP で送る場合は send_headers を使い、キャッシュで付かない場合があることを確認する
- HSTS は短い max-age から、CSP は Report-Only から始めて段階的に強める
- 設定場所は1か所にまとめ、curl と実際の画面操作で確認する