IdeaValue

セキュリティヘッダーの設定方法:X-Frame-Options・nosniff・Referrer-Policy・Permissions-Policy

執筆:IDEAVALU運営 · 更新:

レスポンスヘッダーを数行足すだけで、ブラウザ側の防御を有効にできます。多くの個人開発サイトで未設定のまま公開されている項目です。

各ヘッダーの役割

それぞれ、防いでいるものが違います。

  • X-Frame-Options(または CSP の frame-ancestors):他のサイトに透明な iframe で埋め込まれ、ボタンを押させられる「クリックジャッキング」を防ぎます。
  • X-Content-Type-Options: nosniff:ブラウザがファイルの種類を推測して、画像などをスクリプトとして実行するのを防ぎます。
  • Referrer-Policy:リンク先へ送る URL の範囲を決めます。strict-origin-when-cross-origin なら、外部サイトにはドメインだけが送られ、URL に含まれる ID やトークンが漏れにくくなります。
  • Permissions-Policy:カメラ・マイク・位置情報など、使わないブラウザ機能を無効にします。埋め込んだ外部スクリプトが勝手に使うのを防げます。

自分で確認する方法

次のコマンドで、主なヘッダーをまとめて表示できます。

主なセキュリティヘッダーを表示する

curl -sI https://example.com | grep -iE "x-frame-options|x-content-type-options|referrer-policy|permissions-policy|content-security-policy|strict-transport-security"

バージョン表示と security.txt

Server や X-Powered-By ヘッダーに「nginx/1.18.0」「PHP/7.4」のようなバージョンが出ていると、古い版の既知の脆弱性を狙う手がかりになります。表示を消し、ソフトウェア自体も更新してください。

/.well-known/security.txt に連絡先を書いておくと、脆弱性を見つけた人が報告先に迷いません(RFC 9116)。最低限 Contact と Expires の2行を書きます。

public/.well-known/security.txt の例

Contact: mailto:security@example.com
Expires: 2027-12-31T23:59:59.000Z
Preferred-Languages: ja, en

直し方

クリックジャッキング対策

X-Frame-Options(または CSP の frame-ancestors)で、他サイトへの埋め込みを禁止します。

Next.js の場合

// next.config.mjs
const securityHeaders = [
  { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains' },
  { key: 'X-Frame-Options', value: 'SAMEORIGIN' },
  { key: 'X-Content-Type-Options', value: 'nosniff' },
  { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
  { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
]

export default {
  async headers() {
    return [{ source: '/:path*', headers: securityHeaders }]
  },
}

Vercel で静的サイト・Vite などを公開している場合

// vercel.json(Next.js 以外を Vercel で公開している場合)
{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        { "key": "Strict-Transport-Security", "value": "max-age=63072000; includeSubDomains" },
        { "key": "X-Frame-Options", "value": "SAMEORIGIN" },
        { "key": "X-Content-Type-Options", "value": "nosniff" },
        { "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" },
        { "key": "Permissions-Policy", "value": "camera=(), microphone=(), geolocation=()" }
      ]
    }
  ]
}

Netlify・Cloudflare Pages の場合

# public/_headers(Netlify・Cloudflare Pages)
/*
  Strict-Transport-Security: max-age=63072000; includeSubDomains
  X-Frame-Options: SAMEORIGIN
  X-Content-Type-Options: nosniff
  Referrer-Policy: strict-origin-when-cross-origin
  Permissions-Policy: camera=(), microphone=(), geolocation=()

1つの設定で HSTS・クリックジャッキング・nosniff・Referrer-Policy・Permissions-Policy をまとめて直せます。カメラや位置情報を使うアプリは、Permissions-Policy の該当機能を self に変えてください。

X-Content-Type-Options

X-Content-Type-Options: nosniff を付けます。設定例は上と同じです。

Referrer-Policy

Referrer-Policy: strict-origin-when-cross-origin を付けると、外部サイトにはドメインだけが送られます。設定例は上と同じです。

Permissions-Policy

使わないブラウザ機能を Permissions-Policy で無効にします。設定例は上と同じです。

ソフトウェアのバージョン表示

レスポンスヘッダーからバージョン番号を消します。

nginx の場合

server_tokens off;

Express の場合

app.disable('x-powered-by')

PHP の場合(php.ini)

expose_php = Off

よくある質問

X-Frame-Options と frame-ancestors はどちらを使えばよいですか?
新しいブラウザは CSP の frame-ancestors を優先します。CSP を使っていない場合は X-Frame-Options: SAMEORIGIN を付けておけば十分です。両方付けても問題ありません。
セキュリティヘッダーの設定方法|X-Frame-Options・nosniff など | IDEAVALU