セキュリティヘッダー一覧と設定ガイド|CSP・HSTS・Referrer-Policy・Permissions-Policy
- HTTPS と入力バリデーションだけでは防げない XSS・クリックジャッキング・MIME スニッフィング・リファラー漏洩 は、HTTP レスポンスヘッダーで多層防御できる。
- CSP・HSTS・nosniff・X-Frame-Options・Referrer-Policy・Permissions-Policy の6つを nginx 等で返し、CSP は Report-Only 段階導入、HSTS は短い max-age から段階適用するのが安全な進め方だ。
- 本記事末尾の nginx 完全設定例 をコピーして、自サイトのドメイン・CSP 許可リストだけ調整すれば実務にそのまま使える。
なぜセキュリティヘッダーが必要か
Web アプリケーションの安全性は、認証・入力バリデーション・ORM のパラメータ化などアプリケーション層と、WAF・CDN・TLS などインフラ層の両方で支えられる。しかし最終的に HTML や JavaScript を解釈して動作するのはユーザーのブラウザであり、ここを守る「最後の防波堤」が HTTP セキュリティレスポンスヘッダー だ。
フレームワークが XSS 対策を内蔵していても、設定ミス・サードパーティウィジェット・レガシー API の組み合わせで穴が開くことは珍しくない。ヘッダーはアプリコードを変更しなくてもサイト全体に一括でポリシーを適用できるため、運用コストに対する防御効果が高い。
代表的なリスクと、ヘッダーがカバーする領域は次のとおり。
| リスク | 攻撃の概要 | 主な防御ヘッダー |
|---|---|---|
| XSS | 注入されたスクリプトの実行 | CSP(script-src 等) |
| クリックジャッキング | 透明 iframe による操作すり替え | X-Frame-Options / CSP frame-ancestors |
| SSL ストリッピング | 初回 HTTP 接続への誘導 | HSTS |
| MIME スニッフィング | text/plain 配信ファイルの HTML 解釈 | X-Content-Type-Options: nosniff |
| Referer 漏洩 | URL 内トークン・検索クエリの外部送信 | Referrer-Policy |
| 意図しないデバイス API 利用 | カメラ・位置情報の不正利用 | Permissions-Policy |
| タブナビング攻撃 | window.opener 経由の元ページ操作 | Cross-Origin-Opener-Policy |
OWASP Secure Headers Project や Mozilla Observatory も同種のヘッダー群を推奨している。本記事では実務で最も使うヘッダーに絞り、nginx での完全設定例と securityheaders.com による自己診断までをカバーする。
多層防御(Defense in Depth)としての位置づけ
セキュリティヘッダーはアプリ層の対策を置き換えるものではない。出力時エスケープ・CSRF トークン・HttpOnly Cookie などと組み合わせて初めて効果を発揮する「深層防御(Defense in Depth)」の一層だ。
たとえば CSP が XSS をブロックできなくても nosniff が MIME 混同を防ぎ、Referrer-Policy が漏洩経路を狭める——という具合に、単一の対策失敗で全滅しない構成を目指す。バグバウンティやペネトレーションテストでも、主要ヘッダー未設定は減点・指摘対象になりやすい。
Google Analytics のドメイン変更、Stripe 決済 iframe の追加、新しいサブドメインの立ち上げ——アプリやインフラが変わるたびに CSP の許可リストや HSTS の includeSubDomains 影響を見直す必要がある。CI/CD パイプラインに curl -I によるヘッダー回帰テストを組み込むと、本番反映後の取りこぼしを減らせる。
主要セキュリティヘッダー一覧
| ヘッダー | 主な役割 |
|---|---|
| Content-Security-Policy (CSP) | スクリプト・スタイル・画像・接続先などの読み込み元を許可リストで制限。XSS の最終防御 |
| Strict-Transport-Security (HSTS) | ブラウザに HTTPS 接続を強制。SSL ストリッピング攻撃を抑える |
| X-Content-Type-Options: nosniff | Content-Type ヘッダーに従わせ、MIME スニッフィングによるスクリプト実行を防ぐ |
| X-Frame-Options | 他サイトからの iframe 埋め込みを制限。クリックジャッキング対策(CSP frame-ancestors の後方互換) |
| Referrer-Policy | リンク先へ送る Referer ヘッダーの量を制御。プライバシーとトークン漏洩防止 |
| Permissions-Policy | カメラ・マイク・位置情報・決済 API などブラウザ機能の利用をページ単位で制限 |
| Cross-Origin-Opener-Policy (COOP) | 別オリジンとの window 共有を制限。タブナビング攻撃を抑える |
| Cross-Origin-Resource-Policy (CORP) | 他オリジンからのリソース読み込みを制限。XS-Leaks 対策の補助 |
優先度の目安:
- 最優先(副作用が少ない) —
X-Content-Type-Options: nosniff、Referrer-Policy - 高優先(段階導入推奨) — CSP、HSTS
- 中優先 — X-Frame-Options /
frame-ancestors、Permissions-Policy - 状況依存 — COOP、CORP、Cross-Origin-Embedder-Policy(SharedArrayBuffer 等が必要な場合)
Content-Security-Policy(CSP)
CSP は「どのオリジンから、どの種類のリソースを読み込んでよいか」をブラウザに指示する許可リスト方式のポリシーだ。インライン <script> や未知ドメインの JavaScript、<object> タグ経由のプラグインなど、想定外の実行経路をブロックできる。
代表的なディレクティブ
| ディレクティブ | 役割 | 実務での推奨 |
|---|---|---|
default-src | 他で指定がない場合のデフォルト | 'self' から開始 |
script-src | JavaScript の実行元 | 'self' + nonce または strict-dynamic |
style-src | CSS の読み込み元 | 'self'(Tailwind 等で 'unsafe-inline' が必要な場合あり) |
img-src | 画像の読み込み元 | 'self' data: https: |
connect-src | fetch、XHR、WebSocket など | API エンドポイント・analytics ドメインを明示 |
font-src | Web フォント | 'self' + Google Fonts 等 |
object-src | Flash 等 | 'none' 推奨 |
base-uri | <base> タグの URL | 'self' 推奨(ベースタグ XSS 対策) |
frame-ancestors | このページを iframe で埋め込める親 | 'self' または 'none' |
form-action | フォーム送信先 | 'self' |
upgrade-insecure-requests | HTTP リソースを HTTPS に自動アップグレード | HTTPS 移行中に有用 |
最小構成の例
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; upgrade-insecure-requests
SPA や広告タグなどインラインスクリプトが避けられない場合は nonce や strict-dynamic を検討する。段階導入の手順は次の記事で詳述している。
Google Analytics、Stripe、reCAPTCHA など外部スクリプトのドメインを script-src に忘れると機能が止まる。Report-Only で違反 URL を洗い出してから本番ポリシーに移行すること。XSS 全般の背景は XSS 攻撃と防御の完全ガイド も参照。
CSP 違反の確認方法
DevTools の Console タブに Refused to execute inline script because it violates the following Content Security Policy directive のようなメッセージが出る。本番前は Content-Security-Policy-Report-Only と report-uri / report-to でサーバー側に違反ログを集約し、想定外のブロックを洗い出す。
Strict-Transport-Security(HSTS)
HSTS はブラウザに「このホストには 今後 HTTP ではなく HTTPS で接続せよ」と記憶させるヘッダーだ。ユーザーが一度 HTTPS でアクセスした後は、以降のリクエストが HTTP に送られる前にブラウザが内部で HTTPS へ書き換えるため、SSL ストリッピング(中間者による HTTP への誘導) を抑えられる。
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
| ディレクティブ | 意味 |
|---|---|
max-age | HSTS を有効にする秒数(1年 = 31536000) |
includeSubDomains | サブドメインにも適用 |
preload | HSTS Preload List 登録の前提(申請は別途必要) |
注意点: 証明書期限切れ・HTTP 専用サブドメイン・ロードバランサ設定ミスがある状態で長期 max-age を設定すると、ユーザーがサイトに到達できなくなる。まず max-age=300(5分)で試し、問題なければ 86400 → 31536000 と段階的に延ばす。
Preload まで進める手順・不可逆性の注意は HSTS Preload 設定手順 を参照。
HSTS が効かないケース
- 初回訪問 — ユーザーが一度も HTTPS でアクセスしていない場合、Preload リストに載っていなければ HTTP 接続が成立する
- 平文 HTTP レスポンス — HSTS は HTTPS レスポンスにのみ 付与する。
listen 80の server ブロックに付けても意味がない - 証明書エラー — ユーザーが警告を無視して進めない限り、HSTS ポリシーは更新されない
X-Content-Type-Options: nosniff
nosniff はブラウザに Content-Type ヘッダーを厳密に従わせる 指示だ。text/plain や image/jpeg として配信したファイルが、中身のバイト列から HTML や JavaScript と推測されて実行される MIME スニッフィング を防ぐ。
X-Content-Type-Options: nosniff
nosniff は設定が1行で済み、副作用も少ないため最初に入れるべきヘッダーの一つ。ただし正しい Content-Type をサーバー側で返すこと(.js は application/javascript、.css は text/css など)が前提であり、nosniff だけでは XSS 全体は防げない。
仕組みと落とし穴の詳細は X-Content-Type-Options: nosniff 解説 を参照。
nosniff と nginx の types ブロック
nginx の include mime.types; が正しく読み込まれているか確認する。カスタム拡張子(.wasm、.json など)を追加した場合は types { ... } で明示的に MIME タイプを定義しないと、デフォルトの application/octet-stream になり、nosniff 環境下でブラウザがファイルを解釈できなくなることがある。
X-Frame-Options と frame-ancestors
クリックジャッキング対策として、ページを <iframe> で埋め込めるかを制限する。値は次の3つ(実務では DENY か SAMEORIGIN が主流)。
- DENY — すべての iframe 埋め込みを拒否
- SAMEORIGIN — 同一オリジンのみ許可
- ALLOW-FROM uri — 指定 URI のみ(非推奨・主要ブラウザ非対応)
X-Frame-Options: SAMEORIGIN
CSP の frame-ancestors が設定されている場合、モダンブラウザではそちらが優先される。新規プロジェクトでは frame-ancestors 'self' を CSP に含め、X-Frame-Options は古いブラウザ向けに併記するパターンが多い。
埋め込み要件がある場合
決済ゲートウェイや SNS ウィジェットが自サイトを iframe 埋め込みする要件がある場合は、CSP で frame-ancestors 'self' https://trusted.example のように許可リストを調整する。自サイトが他サイトを iframe で表示する側(決済モーダル等)の場合は、Permissions-Policy の payment 許可リストも合わせて確認する。
Referrer-Policy
リンク先やリソース先へ送る Referer ヘッダーの量を制御する。URL にセッション ID、リセットトークン、検索クエリが含まれる場合、外部サイトへ意図せず漏れるのを防げる。
| Referrer-Policy 値 | 挙動 |
|---|---|
| no-referrer | Referer を一切送らない。最も厳格。アナリティクスへの影響に注意 |
| same-origin | 同一オリジンへの遷移のみフル URL を送る。クロスオリジンでは送らない |
| strict-origin | HTTPS→HTTPS ではオリジンのみ、HTTPS→HTTP では送らない |
| strict-origin-when-cross-origin(推奨) | 同一オリジンはフル URL、クロスオリジンはオリジンのみ、ダウングレード時は送らない |
| origin | 常にスキーム+ホスト+ポートのみ(パスなし) |
| origin-when-cross-origin | 同一オリジンはフル URL、クロスオリジンはオリジンのみ |
| unsafe-url | 常にフル URL を送る(非推奨・トークン漏洩リスク) |
多くの一般サイトでは strict-origin-when-cross-origin がバランス良いデフォルトだ。
Referrer-Policy: strict-origin-when-cross-origin
<meta name="referrer"> や <a referrerpolicy="..."> でも指定できるが、HTTP レスポンスヘッダーで全ページに統一する方が管理しやすい。<meta> とヘッダーが矛盾すると、要素ごとに挙動が分かれてデバッグが難しくなる。
Permissions-Policy
旧称 Feature-Policy。ブラウザ機能(カメラ、マイク、位置情報、フルスクリーン、決済 API など)を ページ単位・iframe 単位で無効化できる。括弧内が空 () なら全面禁止、self なら同一オリジンのみ許可、* で全オリジン許可だ。
一般サイト向け(不要 API をすべて閉じる)
Permissions-Policy: accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()
WebRTC・地図を使うサービス向け
Permissions-Policy: camera=(self), microphone=(self), geolocation=(self), payment=()
決済 iframe を許可する EC サイト向け
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(self "https://js.stripe.com")
サードパーティ iframe に機能を渡したい場合は、許可するオリジンを明示する。* は便利だが攻撃面が広がるため、本番では極力避ける。
よく使う機能名の一覧
| 機能名 | 制御対象 |
|---|---|
camera | カメラアクセス |
microphone | マイクアクセス |
geolocation | 位置情報 API |
payment | Payment Request API |
fullscreen | フルスクリーン表示 |
usb | WebUSB |
accelerometer / gyroscope / magnetometer | センサー系 |
interest-cohort | FLoC 等(非推奨機能の無効化に使用) |
Cross-Origin-Opener-Policy(COOP)と Cross-Origin-Resource-Policy(CORP)
モダンブラウザ向けの追加ヘッダー。必須ではないが、XS-Leaks(クロスサイトリーク)対策や Spectre 緩和の文脈で採用が増えている。
Cross-Origin-Opener-Policy
Cross-Origin-Opener-Policy: same-origin
別オリジンで開いたページとの window.opener 参照を切り離し、タブナビング攻撃(新しいタブで開いた悪意あるページが元ページを window.opener.location で書き換える)を防ぐ。外部リンクを target="_blank" で開く場合は、併せて <a rel="noopener noreferrer"> を付けるのが定石。
Cross-Origin-Resource-Policy
Cross-Origin-Resource-Policy: same-origin
自サイトのリソース(JS、CSS、画像)が他オリジンのページから <script> や <img> で読み込まれることを制限する。CDN 経由で静的アセットを配信している場合、CORP を厳しくしすぎると正当な埋め込みもブロックされるため、段階的に導入する。
非推奨・レガシーヘッダー
X-XSS-Protection
X-XSS-Protection: 1; mode=block
Internet Explorer 時代の XSS フィルタ用。Chrome 等は非推奨・無効化済みであり、新規プロジェクトでは設定しない。CSP が上位互換の防御手段だ。
Public-Key-Pins(HPKP)
証明書ピン留め用。ブラウザから削除済み。HSTS Preload と正しい証明書運用で代替する。
nginx 完全設定例
以下は HTTP→HTTPS リダイレクト、SSL/TLS、6 大セキュリティヘッダー、静的ファイル、SPA フォールバック、CSP Report-Only 移行用コメント まで含む nginx 完全例だ。example.com を自ドメインに置き換え、証明書パスを環境に合わせて調整する。
# /etc/nginx/sites-available/example.com
# ── 平文 HTTP → HTTPS 301 リダイレクト ──
# HSTS はここには付けない(HTTPS レスポンスのみ有効)
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://example.com$request_uri;
}
# ── www → apex 正規化(任意) ──
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
return 301 https://example.com$request_uri;
}
# ── メイン HTTPS サーバー ──
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com;
# ── SSL/TLS 基本設定 ──
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
root /var/www/example.com/dist;
index index.html;
# ── セキュリティヘッダー(server レベルで一括付与) ──
# always を付けると 4xx/5xx レスポンスにもヘッダーが付く
# Content-Security-Policy
# 移行期間中は下の Report-Only 行を有効にし、本番行をコメントアウトする
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://www.google-analytics.com; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'self'; upgrade-insecure-requests" always;
# CSP 段階導入用(本番前はこちらを有効化)
# add_header Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self'; report-uri https://example.com/csp-report" always;
# HTTP Strict Transport Security
# 最初は max-age=300 から。問題なければ 86400 → 31536000 へ延長
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# MIME スニッフィング防止
add_header X-Content-Type-Options "nosniff" always;
# クリックジャッキング防止
add_header X-Frame-Options "SAMEORIGIN" always;
# Referer 漏洩制御
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# ブラウザ API 制限
add_header Permissions-Policy "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=()" always;
# タブナビング攻撃対策(任意)
add_header Cross-Origin-Opener-Policy "same-origin" always;
# ── 静的アセット(長期キャッシュ) ──
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|webp|woff2?)$ {
expires 1y;
add_header Cache-Control "public, immutable";
# location 内で add_header を書くと server の add_header が消えるため再宣言
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
try_files $uri =404;
}
# ── API プロキシ(バックエンドへ転送) ──
location /api/ {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# プロキシ先でもヘッダーが必要なら再宣言
add_header X-Content-Type-Options "nosniff" always;
}
# ── SPA フォールバック ──
location / {
try_files $uri $uri/ /index.html;
}
# ── セキュリティ: 隠しファイル拒否 ──
location ~ /\. {
deny all;
}
}
設定反映後は nginx -t で構文チェックし、systemctl reload nginx で再読み込みする。
nginx 設定時の落とし穴
| 問題 | 原因 | 対処 |
|---|---|---|
| エラーページだけ CSP が効かない | add_header に always がない | すべての add_header に always を付ける |
| location 内でヘッダーが消える | nginx の add_header 継承ルール | 各 location に必要なヘッダーを再宣言するか、headers-more モジュールの more_set_headers を使う |
| CSP と Report-Only の併用 | 移行期間の設定ミス | 本番 CSP と Report-Only を同時に有効にし、Report-Only 側に緩いポリシー + report-uri を設定 |
| HTTP server に HSTS | 仕様上無意味 | HSTS は listen 443 の server ブロックのみ |
| 二重ヘッダー | CDN と nginx の両方で付与 | どちらか一方で一元管理 |
Cloudflare の Transform Rules、Vercel の vercel.json headers、Netlify の _headers でも同等の値を返せる。CDN と nginx の二重付与は避け、どちらか一方で管理する。
Cloudflare での同等設定(参考)
Cloudflare ダッシュボード → Rules → Transform Rules → Modify Response Header で、nginx と同じヘッダー名・値を追加できる。Cloudflare の HSTS 設定(SSL/TLS → Edge Certificates)と nginx の HSTS が重複しないよう、Edge か Origin のどちらか一方に集約する。
ヘッダー確認コマンド
本番反映前後に、コマンドラインでヘッダーを確認する。
# 全レスポンスヘッダーを表示
curl -sI https://example.com
# 特定ヘッダーのみ抽出
curl -sI https://example.com | grep -iE 'content-security|strict-transport|x-content-type|x-frame|referrer|permissions'
# 404 ページでもヘッダーが付くか確認
curl -sI https://example.com/this-page-does-not-exist
# HTTP リダイレクトチェーン(HSTS 前の 301 を確認)
curl -sI http://example.com
DevTools の Network タブ → 対象リクエスト → Response Headers でも同じ情報が確認できる。キャッシュの影響を避けるため、シークレットウィンドウまたは Disable cache を有効にする。
securityheaders.com スキャン結果の読み方
securityheaders.com に URL を入力すると、レスポンスヘッダーを解析して A+ 〜 F のスコアと項目別の評価が返る。本番反映前後の自己診断に使いやすい。
スコアと評価記号
| 記号 | 意味 |
|---|---|
| A+ / A | 主要ヘッダーが揃い、値も推奨に近い |
| B〜C | 一部ヘッダー欠落、または値が緩い(Referrer-Policy 未設定など) |
| D〜F | CSP・HSTS など重要ヘッダーが未設定、または危険な値 |
各項目は 緑(OK)・黄(改善余地)・赤(未設定/危険) で表示される。
- Content-Security-Policy — 未設定なら赤。
unsafe-inlineや*だと黄。厳格な許可リストで緑 - Strict-Transport-Security — 未設定なら赤。
max-ageが 7776000(90日)未満だと黄。includeSubDomainsがあると加点 - X-Content-Type-Options —
nosniffが無いと黄〜赤 - X-Frame-Options — 未設定なら黄。
DENYまたはSAMEORIGINで緑 - Referrer-Policy — 未設定なら黄。
unsafe-urlは減点 - Permissions-Policy — 未設定でも大きく減点されないことが多いが、設定すると加点
スキャン結果を鵜呑みにしない理由
securityheaders.com はヘッダーの存在と形式を見るツールであり、アプリの XSS 脆弱性そのものは検出しない。A+ でもアプリ層に穴があれば攻撃は成立する。逆に CSP が厳しすぎてサイトが壊れている場合でも、ヘッダーさえ返っていれば高得点になる。
実務では スキャン → DevTools で生ヘッダー確認 → 主要フローの手動テスト の3段階で確認する。Mozilla Observatory を併用すると、TLS 設定やリダイレクトチェーンも含めた評価が得られる。
トラブルシューティング
CSP で外部サービスが動かなくなった
- DevTools Console の CSP 違反メッセージからブロックされた URL を特定
- ドメインを該当ディレクティブ(
script-src、connect-src、frame-src等)に追加 - Report-Only で再検証してから本番 CSP を更新
HSTS 設定後にサイトにアクセスできない
- 証明書の有効期限・SAN(Subject Alternative Name)を確認
includeSubDomains配下に HTTP 専用サブドメインがないか棚卸し- 一時的に
max-age=0を返して HSTS を解除(Preload 登録済みの場合は解除に数ヶ月かかる)
iframe 埋め込みがブロックされた
X-Frame-Options: DENYになっていないか確認- CSP の
frame-ancestorsに許可すべき親オリジンが含まれているか確認 - サードパーティ側(Stripe 等)の埋め込み要件ドキュメントと照合
add_header が location で消える
nginx の仕様上、location ブロック内で add_header を1つでも書くと、親 server の add_header はすべて無効になる。静的ファイル用 location でもセキュリティヘッダーを再宣言するか、OpenResty / headers-more モジュールで more_set_headers を使う。
本番適用前のチェックリスト
curl -I https://example.com または DevTools で現在のレスポンスヘッダーを記録する
CSP を Content-Security-Policy-Report-Only で追加し、1〜2週間違反レポートを観測する
HSTS を max-age=300 から始め、証明書自動更新と HTTP→HTTPS 301 を確認してから延長する
外部 iframe(決済・地図・SNS)が frame-ancestors / X-Frame-Options でブロックされないか確認する
404/500 エラーページにもセキュリティヘッダーが付いているか curl で確認する
CDN と nginx で同じヘッダーが二重付与されていないか確認する
securityheaders.com と Mozilla Observatory でスコアを確認する
ログイン・決済・フォーム送信・ファイルアップロードなど主要フローをステージングで手動再テストする
関連記事
この記事は セキュリティ テーマの一環です。あわせて読むと理解が深まる関連記事をまとめました。
| トピック | 記事 |
|---|---|
| Double Submit Cookie完全実装 | Double Submit Cookie完全実装|Synchronizer Token比較・SPA+JWT・サブドメイン攻撃 |
| CORSエラーの対処法 | CORSエラーの対処法|「Access-Control-Allow-Origin」で解決する |
| CORSプリフライトリクエスト | CORSプリフライトリクエスト|OPTIONSが飛ぶ条件と正しい応答 |
| ローカル開発でCORSエラーが出る原因と3つの回避策 | ローカル開発でCORSエラーが出る原因と3つの回避策 |
| OAuth2 PKCE SPA実装ガイド | OAuth2 PKCE SPA実装ガイド|Authorization Code + S256 + BFFパターン |
| Passkeys・WebAuthn実装の基礎 | Passkeys・WebAuthn実装の基礎|FIDO2・Resident Key・@simplewebauthn/server |
| JWTのデバッグ方法 | JWTのデバッグ方法|トークンの中身を安全に確認する |
| JWTの中身を確認する方法 | JWTの中身を確認する方法|改ざんが検知される仕組み |
| JWKSとJWT鍵ローテーション運用ガイド | JWKSとJWT鍵ローテーション運用ガイド|kid検証・ゼロダウンタイム・Node.js実装 |
| Subresource Integrity (SRI) 完全ガイド | Subresource Integrity (SRI) 完全ガイド|CDN スクリプトの integrity・crossorigin・フォールバック |
| Permissions-Policy 完全ガイド | Permissions-Policy 完全ガイド|iframe・camera・microphone・geolocation・allow 属性 |
| DNSリバインディング攻撃の防御 | DNSリバインディング攻撃の防御|Host検証・SameSite・Private Network Access・localhostバインド |
まとめ
セキュリティヘッダーは「一度設定して終わり」ではなく、CDN 追加・アプリ改修・サブドメイン増設のたびに見直す運用資産だ。CSP に新しい analytics ドメインを足したら connect-src を更新し、サブドメインを増やしたら HSTS の includeSubDomains の影響を再確認する。
実務チェックリスト:
- CSP — Report-Only 段階導入 → 本番。CSP 設定ガイド を参照。
object-src 'none'とbase-uri 'self'は基本セット - HSTS — 証明書自動更新を確認してから長期 max-age。Preload 手順 は任意
- nosniff — 副作用が少ないので最優先で追加。詳細解説
- X-Frame-Options / frame-ancestors — 埋め込み要件に合わせて SAMEORIGIN か DENY
- Referrer-Policy —
strict-origin-when-cross-originをデフォルト候補に - Permissions-Policy — 使わない API は
()で閉じる - COOP — 外部リンクを
target="_blank"で開くサイトはsame-originを検討
6 つを nginx 等で揃え、securityheaders.com で計測し、ステージングでテストを経て本番へ展開しよう。アプリ層のエスケープ・認証・CSRF 対策と組み合わせることで、OWASP が推奨する多層防御の土台が整う。