スタティックサイト向けCSP
2026年のスタティックサイトで実際に重要なディレクティブ、およびgautamkhorana.comのFAL + Supabase + Pagefind プレイブック。
CSPの目的
Content Security Policyはブラウザにページのリソースをロードできるオリジンを伝えるHTTPヘッダーです。正しく設定すれば、ほとんどのXSS、クリックジャッキング、サプライチェーン攻撃を防げます。間違って設定すると、診断に何日もかかるような方法で静かに機能を壊してしまいます。
スタティックサイトは認識されるリスクが低いため、CSPのドキュメント化が不足しがちです。実際のところ、CSPディレクティブが不足しているスタティックサイトは、動画再生、画像読み込み、検索機能、またはフォントレンダリングが壊れる可能性があり、ブラウザコンソールメッセージがあなたが得られる唯一のシグナルです。
リソースタイプごとのマッピング
各リソースタイプを制御するディレクティブ:
img-srcはimgタグ用。media-srcはvideo、audio、sourceエレメント用。frame-srcはiframe用。connect-srcはfetchとWebSocket用。script-srcはscriptタグ用。style-srcはstyleタグとlink rel=stylesheet用。font-srcは@font-face用。
重要:default-src "self"はサードパーティホストからのビデオをカバーしていない。Supabase Storageからのビデオはmedia-srcを忘れるとポスター画像だけ表示されて音声が出ない。ブラウザコンソールにはそのディレクティブがブロックしたことが表示される。ビデオが謎に再生されない場合はまずそこを確認するのだ。
2026年5月のインシデント
gautamkhorana.comで2026年5月、Supabase Storageにホストされたkling MP4はHTMLを正しく描画したが再生されなかった。ポスター画像は表示される。ビデオは開始されない。20分のデバッグの後、答えはCSPにmedia-srcディレクティブがなく、ブラウザがビデオエレメントを静かにブロックしていたというものだった。
修正はnetlify.tomlへの1行追加だった:media-src "self" https://*.supabase.co。ポスター表示なしの再生不可のシンプトムがキーパターン:CSPが画像は許可しているがビデオは許可していないという意味。
静的サーチライブラリはwasmとworkerパーミッションが必要
Pagefind、Stork、Tinysearch、その他の静的サイト検索ライブラリはWebAssemblyプラスWeb Workersを使う。CSPはscript-src "wasm-unsafe-eval"とworker-src "self" blob:を含む必要があり、そうしないと検索は「検索中...」で永遠にハング状態になり、コンソールエラーは出ない。
gautamkhorana.comで2026年5月の2番目のインシデント:wasmがブロックされたときpagefind.init()が静かに失敗したため、サーチドロワーが「検索中...」で止まっていた。修正はscript-srcに "wasm-unsafe-eval"を追加してworker-srcに "self" blob:を追加することだった。
FAL + Supabase + Pagefindサイト向けの最小限必須CSP
必須:
img-src self https://*.supabase.co https://*.fal.media(ヒーロー画像とFAL生成アセット用)、media-src self https://*.supabase.co(動画用)、connect-src self https://*.supabase.co(Supabase APIコール用)、script-src self "wasm-unsafe-eval"(Pagefind用)、worker-src self blob:(Pagefindワーカー用)、style-src self "unsafe-inline"(Astroスコープ付きスタイル用)、font-src self(自ホスト型フォント用)。
新しいアセットホスト(Cloudinary、Bunny、R2など)を追加するたびに、netlify.tomlまたはvercel.jsonを監査し、そのリソースタイプが使用する可能性のあるすべてのディレクティブにホストを追加してください。これを間違えるとサイレント破損が起こり、本番環境で浮上します。
CSP変更のテスト
CSP-Report-Onlyモードを使うと、本番環境でポリシー変更をテストでき、何も壊れません。ブラウザはリクエストをブロックする代わりに、違反をレポートエンドポイントにログします。新しいディレクティブをレポート専用で1週間実行し、違反を確認してから、強制モードに昇格させてください。
ほとんどのCSP失敗は本番環境ではサイレントです。レポートエンドポイントが、実際に何を壊してしまったかを知る唯一の方法です。重要でないCSP変更を本番に出す前に、必ず設定してください。