セキュリティヘッダー一覧と設定ガイド|CSP・HSTS・Referrer-Policy・Permissions-Policy

(更新: 2026年6月21日 ) セキュリティ HTTPヘッダー CSP HSTS Web nginx
結論
  • 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注入されたスクリプトの実行CSPscript-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 ProjectMozilla 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 対策の補助

優先度の目安:

  1. 最優先(副作用が少ない)X-Content-Type-Options: nosniffReferrer-Policy
  2. 高優先(段階導入推奨) — CSP、HSTS
  3. 中優先 — X-Frame-Options / frame-ancestors、Permissions-Policy
  4. 状況依存 — COOP、CORP、Cross-Origin-Embedder-Policy(SharedArrayBuffer 等が必要な場合)

Content-Security-Policy(CSP)

CSP は「どのオリジンから、どの種類のリソースを読み込んでよいか」をブラウザに指示する許可リスト方式のポリシーだ。インライン <script> や未知ドメインの JavaScript、<object> タグ経由のプラグインなど、想定外の実行経路をブロックできる。

代表的なディレクティブ

ディレクティブ役割実務での推奨
default-src他で指定がない場合のデフォルト'self' から開始
script-srcJavaScript の実行元'self' + nonce または strict-dynamic
style-srcCSS の読み込み元'self'(Tailwind 等で 'unsafe-inline' が必要な場合あり)
img-src画像の読み込み元'self' data: https:
connect-srcfetch、XHR、WebSocket などAPI エンドポイント・analytics ドメインを明示
font-srcWeb フォント'self' + Google Fonts 等
object-srcFlash 等'none' 推奨
base-uri<base> タグの URL'self' 推奨(ベースタグ XSS 対策)
frame-ancestorsこのページを iframe で埋め込める親'self' または 'none'
form-actionフォーム送信先'self'
upgrade-insecure-requestsHTTP リソースを 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 や広告タグなどインラインスクリプトが避けられない場合は noncestrict-dynamic を検討する。段階導入の手順は次の記事で詳述している。

CSP 導入時の注意

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-Onlyreport-uri / report-to でサーバー側に違反ログを集約し、想定外のブロックを洗い出す。

Strict-Transport-Security(HSTS)

HSTS はブラウザに「このホストには 今後 HTTP ではなく HTTPS で接続せよ」と記憶させるヘッダーだ。ユーザーが一度 HTTPS でアクセスした後は、以降のリクエストが HTTP に送られる前にブラウザが内部で HTTPS へ書き換えるため、SSL ストリッピング(中間者による HTTP への誘導) を抑えられる。

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
ディレクティブ意味
max-ageHSTS を有効にする秒数(1年 = 31536000)
includeSubDomainsサブドメインにも適用
preloadHSTS 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/plainimage/jpeg として配信したファイルが、中身のバイト列から HTML や JavaScript と推測されて実行される MIME スニッフィング を防ぐ。

X-Content-Type-Options: nosniff

nosniff は設定が1行で済み、副作用も少ないため最初に入れるべきヘッダーの一つ。ただし正しい Content-Type をサーバー側で返すこと(.jsapplication/javascript.csstext/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
paymentPayment Request API
fullscreenフルスクリーン表示
usbWebUSB
accelerometer / gyroscope / magnetometerセンサー系
interest-cohortFLoC 等(非推奨機能の無効化に使用)

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_headeralways がないすべての add_headeralways を付ける
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 ダッシュボード → RulesTransform RulesModify 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〜FCSP・HSTS など重要ヘッダーが未設定、または危険な値

各項目は 緑(OK)・黄(改善余地)・赤(未設定/危険) で表示される。

  • Content-Security-Policy — 未設定なら赤。unsafe-inline* だと黄。厳格な許可リストで緑
  • Strict-Transport-Security — 未設定なら赤。max-age が 7776000(90日)未満だと黄。includeSubDomains があると加点
  • X-Content-Type-Optionsnosniff が無いと黄〜赤
  • X-Frame-Options — 未設定なら黄。DENY または SAMEORIGIN で緑
  • Referrer-Policy — 未設定なら黄。unsafe-url は減点
  • Permissions-Policy — 未設定でも大きく減点されないことが多いが、設定すると加点

スキャン結果を鵜呑みにしない理由

securityheaders.com はヘッダーの存在と形式を見るツールであり、アプリの XSS 脆弱性そのものは検出しない。A+ でもアプリ層に穴があれば攻撃は成立する。逆に CSP が厳しすぎてサイトが壊れている場合でも、ヘッダーさえ返っていれば高得点になる。

実務では スキャン → DevTools で生ヘッダー確認 → 主要フローの手動テスト の3段階で確認する。Mozilla Observatory を併用すると、TLS 設定やリダイレクトチェーンも含めた評価が得られる。

トラブルシューティング

CSP で外部サービスが動かなくなった

  1. DevTools Console の CSP 違反メッセージからブロックされた URL を特定
  2. ドメインを該当ディレクティブ(script-srcconnect-srcframe-src 等)に追加
  3. Report-Only で再検証してから本番 CSP を更新

HSTS 設定後にサイトにアクセスできない

  1. 証明書の有効期限・SAN(Subject Alternative Name)を確認
  2. includeSubDomains 配下に HTTP 専用サブドメインがないか棚卸し
  3. 一時的に max-age=0 を返して HSTS を解除(Preload 登録済みの場合は解除に数ヶ月かかる)

iframe 埋め込みがブロックされた

  1. X-Frame-Options: DENY になっていないか確認
  2. CSP の frame-ancestors に許可すべき親オリジンが含まれているか確認
  3. サードパーティ側(Stripe 等)の埋め込み要件ドキュメントと照合

add_header が location で消える

nginx の仕様上、location ブロック内で add_header を1つでも書くと、親 serveradd_headerすべて無効になる。静的ファイル用 location でもセキュリティヘッダーを再宣言するか、OpenResty / headers-more モジュールで more_set_headers を使う。

本番適用前のチェックリスト

1

curl -I https://example.com または DevTools で現在のレスポンスヘッダーを記録する

2

CSP を Content-Security-Policy-Report-Only で追加し、1〜2週間違反レポートを観測する

3

HSTS を max-age=300 から始め、証明書自動更新と HTTP→HTTPS 301 を確認してから延長する

4

外部 iframe(決済・地図・SNS)が frame-ancestors / X-Frame-Options でブロックされないか確認する

5

404/500 エラーページにもセキュリティヘッダーが付いているか curl で確認する

6

CDN と nginx で同じヘッダーが二重付与されていないか確認する

7

securityheaders.com と Mozilla Observatory でスコアを確認する

8

ログイン・決済・フォーム送信・ファイルアップロードなど主要フローをステージングで手動再テストする

関連記事

この記事は セキュリティ テーマの一環です。あわせて読むと理解が深まる関連記事をまとめました。

トピック記事
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 の影響を再確認する。

実務チェックリスト:

  • CSPReport-Only 段階導入 → 本番。CSP 設定ガイド を参照。object-src 'none'base-uri 'self' は基本セット
  • HSTS — 証明書自動更新を確認してから長期 max-age。Preload 手順 は任意
  • nosniff — 副作用が少ないので最優先で追加。詳細解説
  • X-Frame-Options / frame-ancestors — 埋め込み要件に合わせて SAMEORIGIN か DENY
  • Referrer-Policystrict-origin-when-cross-origin をデフォルト候補に
  • Permissions-Policy — 使わない API は () で閉じる
  • COOP — 外部リンクを target="_blank" で開くサイトは same-origin を検討

6 つを nginx 等で揃え、securityheaders.com で計測し、ステージングでテストを経て本番へ展開しよう。アプリ層のエスケープ・認証・CSRF 対策と組み合わせることで、OWASP が推奨する多層防御の土台が整う。