Header set vs Header always set
| ディレクティブ | 適用範囲 |
|---|---|
Header set |
成功レスポンス(200系)のみ |
Header always set |
エラーレスポンス(403 / 404 等)にも付与 |
セキュリティヘッダーは
Header always setを使う。エラーページでもブラウザに安全な動作を指示するため、alwaysが必須。
HSTS(HTTP Strict Transport Security)
Header always set Strict-Transport-Security \
"max-age=63072000; includeSubDomains; preload" \
"expr=%{HTTPS} == 'on' || %{HTTP:X-Forwarded-Proto} == 'https'"
役割
ブラウザに「今後必ず HTTPS で接続してください」と宣言するヘッダー。
.htaccess の HTTPS リダイレクトはリクエストがサーバーに到達してからリダイレクトを行う。HSTS はブラウザ側で事前に HTTPS 化するため、中間者攻撃(MITM)のリスクをゼロにできる。
各パラメータの意味
| パラメータ | 意味 |
|---|---|
max-age=63072000 |
HSTS ポリシーを保持する期間(秒)。63072000 秒 = 2年 |
includeSubDomains |
サブドメインにも HSTS を適用する |
preload |
ブラウザの HSTS プリロードリストへの登録を許可する(初回アクセスも HTTPS 化) |
expr= 条件の役割(Nginx リバースプロキシ対応)
XServer・ConoHa WING などのレンタルサーバーは Nginx → Apache のリバースプロキシ構成を採用している。この場合、ユーザーが HTTPS
でアクセスしてもサーバーの Apache は HTTP で受け取るため、%{HTTPS} だけでは判定できない。
ユーザー →(HTTPS)→ Nginx(TLS終端) →(HTTP)→ Apache
expr= 条件は Apache の式(Expression)評価エンジンを使い、HTTPS 接続または
X-Forwarded-Proto: https のどちらかが成立する場合のみヘッダーを送信する。これにより HTTP アクセス時に HSTS
ヘッダーが送られることを防ぐ。
includeSubDomainsを有効にする前に、すべてのサブドメインが HTTPS に対応していることを確認する。対応していないサブドメインにアクセスできなくなる。
CSP(Content Security Policy)
Header always set Content-Security-Policy "upgrade-insecure-requests;"
upgrade-insecure-requests の役割
ページ内の http:// リソース(画像・CSS・JS など)を自動的に https:// に変換する指示。Mixed
Content(HTTP と HTTPS が混在するページ)を自動修正するために使う。
ソースディレクティブの概要
CSP はリソースの読み込み元を制限するディレクティブを持つ。WordPress サイトに本格的な CSP を導入する場合は以下に注意が必要。
| ディレクティブ | 制限対象 |
|---|---|
default-src |
他のディレクティブのフォールバック(指定がない場合に適用) |
script-src |
JavaScript の読み込み元 |
style-src |
CSS の読み込み元 |
img-src |
画像の読み込み元 |
font-src |
フォントの読み込み元 |
connect-src |
Ajax / Fetch / WebSocket の接続先 |
WordPress 固有の注意点
WordPress はコアと多くのプラグインがインラインスクリプト・eval() を使用するため、script-src に
'unsafe-inline' や 'unsafe-eval' が必要になるケースが多い。CSP を強化する場合は nonce
ベースの実装が推奨されるが、多くのプラグインとの互換性を維持するのは難しい。
img-src と OG image の落とし穴
img-src を明示すると default-src のフォールバックが効かなくなる。以下のミスに注意する。
# NG: 'self' を入れ忘れると自サイト画像もブロックされる
img-src data:
# OK: 必ず 'self' を含める
img-src 'self' data:
OG image(SNS シェア時に使われるサムネイル画像)もブロック対象になる。
img-srcを書くなら必ず'self'を含める。
Report-Only モード
いきなり本番環境に CSP を適用するとサイトが壊れるリスクがある。まず Content-Security-Policy-Report-Only
ヘッダーでテストし、違反レポートを確認してから本番適用するのが安全。
# テスト用(実際のブロックは行わず、違反をレポートのみ)
Header always set Content-Security-Policy-Report-Only "default-src 'self'; report-uri /csp-report"
Report-Only モードでは
upgrade-insecure-requestsは無視される。これはアクション指示(リソースのアップグレード)であり、制限指示ではないため。本番 CSP にのみ含める。
X-Content-Type-Options
Header always set X-Content-Type-Options "nosniff"
役割と防御対象
ブラウザが MIME タイプを自動推測(MIME スニッフィング)する機能を無効にするヘッダー。
MIME スニッフィングを悪用した攻撃として、画像ファイルに偽装した JavaScript をアップロードしてブラウザに実行させる XSS
攻撃がある。nosniff を指定すると、サーバーが返す Content-Type
ヘッダーの値をブラウザが厳格に遵守するため、この攻撃を防げる。
X-Frame-Options
Header always set X-Frame-Options "SAMEORIGIN"
役割と防御対象
他サイトがこのサイトのページを <iframe> で埋め込むことを制限するヘッダー。クリックジャッキング攻撃を防止する。
クリックジャッキングとは、攻撃者が自分のサイトに対象サイトを透明な iframe で重ね、ユーザーに見えないボタンをクリックさせる攻撃手法。
設定値の意味
| 値 | 意味 |
|---|---|
SAMEORIGIN |
同一オリジンからの埋め込みのみ許可(推奨) |
DENY |
すべての埋め込みを禁止 |
Referrer-Policy
Header always set Referrer-Policy "strict-origin-when-cross-origin"
役割
リンクを踏んで他サイトに移動したとき、ブラウザが Referer ヘッダーにどれだけの情報を含めるかを制御するヘッダー。URL
には管理画面のパスや個人情報を含む場合があり、外部サイトへの漏洩を防ぐ。
strict-origin-when-cross-origin の動作
| 移動先 | 送信内容 |
|---|---|
| 同一オリジン(自サイト内) | 完全な URL(パスを含む)を送信 |
| 外部オリジン(https→https) | オリジン部分のみ送信(https://example.com) |
| 外部オリジン(https→http) | 何も送信しない |
Permissions-Policy
Header always set Permissions-Policy \
"camera=(), microphone=(), payment=(), usb=()"
役割
ブラウザが持つ強力な API(カメラ・マイク・決済など)の使用を制限するヘッダー。WordPress サイトで通常使用しないデバイス API を無効化することで、マルウェアや XSS 攻撃が不正にこれらの API を呼び出すことを防ぐ。
空の括弧 () はそのディレクティブを完全に無効化することを意味する(すべてのオリジンからの使用を禁止)。
防御マップ — 各ヘッダーの担当範囲
┌── HSTS ──────────── HTTP→HTTPS 強制(ブラウザレベル)
├── CSP ───────────── Mixed Content 自動修正 + リソース制限
├── X-Content-Type ── MIME 偽装による XSS 防止
├── X-Frame-Options ─ クリックジャッキング防止
├── Referrer-Policy ─ URL 情報の漏洩制御
└── Permissions ───── デバイス API の不正利用防止
これらのヘッダーはすべてレスポンスヘッダーとして mod_headers
モジュールで出力する。<IfModule mod_headers.c> でラップすることで、モジュールが無効な環境でも 500 エラーを防げる。
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" "expr=%{HTTPS} == 'on' || %{HTTP:X-Forwarded-Proto} == 'https'"
Header always set Content-Security-Policy "upgrade-insecure-requests;"
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=(), payment=(), usb=()"
</IfModule>