このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docsコミュニティーについてもっと知り、仲間になるにはこちらから。
コンテンツセキュリティポリシー (CSP)
コンテンツセキュリティポリシー (CSP) は、特定の種類のセキュリティ脅威のリスクを防止または最小限に抑えるのに役立つ機能です。これは、ウェブサイトからブラウザーへの一連の指示で構成されており、サイトを構成するコードが実行できることを制限するようにブラウザーに指示します。
CSP の主な用途は、文書が読み込むことを許可するリソース、特に JavaScript リソースを制御することです。これは主に、攻撃者が被害者のサイトに悪意のあるコードを注入するクロスサイトスクリプティング (XSS) 攻撃に対する防御として使用されます。
CSP には他にも、クリックジャッキングからの防御や、サイトのページが HTTPS 経由で確実に読み込まれるようにするなどの目的があります。
このガイドでは、 CSP がブラウザーに配信される仕組みと、その概要を見ていくことから始めます。
次に、XSS から保護するために読み込むリソースを制御するために使用する方法、そしてクリックジャッキングからの保護や保護されていないリクエストのアップグレードなど、それ以外の使用例について記述します。異なる使用例間に依存関係はないことに注意してください。クリックジャッキングからの保護を追加したいが、 XSS の緩和は追加したくない場合は、その使用例に対応するディレクティブを追加するだけで済みます。
最後に、CSP を展開するための戦略と、このプロセスを容易にするツールについて説明します。
In this article
CSP の概要
CSP は、Content-Security-Policy レスポンスヘッダーでブラウザーに配信する必要があります。これは、メイン文書だけでなく、すべてのリクエストに対するすべてのレスポンスに設定する必要があります。
また、文書の<meta> 要素のhttp-equiv 属性を使用して指定することもできます。これは、静的リソースのみを持つクライアント側でレンダリングされる単一ページアプリなど、サーバーインフラストラクチャに依存することを避けたい場合などに便利なオプションです。ただし、このオプションは CSP のすべての機能に対応しているわけではありません。
ポリシーは、セミコロンで区切られた一連の「ディレクティブ」として指定します。各ディレクティブは、セキュリティポリシーの異なる側面を制御します。各ディレクティブには、名前、その後に空白、その後に値が続きます。ディレクティブによって構文が異なる場合があります。
例えば、次の CSP を考えてみましょう。
Content-Security-Policy: default-src 'self'; img-src 'self' example.comこれは 2 つのディレクティブを設定します。
default-srcディレクティブを'self'に設定img-srcディレクティブを'self' example.comに設定
最初のディレクティブdefault-src は、それよりも具体的なディレクティブで他のリソースタイプに対して別のポリシーが設定されていない限り、文書と同じオリジンを持つリソースのみを読み込むようブラウザーに指示します。 2 番目のimg-src は、同じオリジンを持つ画像、またはexample.com から提供されている画像を読み込むようブラウザーに指示します。
次の節では、 CSP の主な機能であるリソースの読み込みを制御するために利用できるツールを見ていきます。
リソース読み込みの制御
CSP を使用して、文書が読み込むことを許可されるリソースを制御することができます。これは主に、クロスサイトスクリプティング (XSS) 攻撃からの保護に使用されます。
この節では、リソースの読み込みを制御することで XSS から保護する方法について最初に説明し、次に CSP が提供する、読み込むリソースを制御するためのツールについて説明します。最後に、「厳格な CSP」と呼ばれる、推奨される具体的な戦略について記述します。
XSS とリソース読み込み
クロスサイトスクリプティング (XSS) 攻撃とは、攻撃者がターゲットのウェブサイトのコンテキストで自分のコードを実行できる攻撃です。このコードは、例えば、次のような、ウェブサイトのコード自体ができるあらゆることを実行することができます。
- サイトに読み込まれたページのコンテンツにアクセスまたは変更する
- ローカルストレージ内のコンテンツにアクセスまたは変更する
- ユーザーの資格情報を使用して HTTP リクエストを行い、ユーザーを偽装したり、機密データにアクセスしたりする
XSS 攻撃は、攻撃者が作成した可能性のある入力 (URL 引数やブログ投稿のコメントなど) をウェブサイトが受け入れて、それをサニタイジングせずにページに記載した場合、つまり JavaScript として実行されないことを確実にしない場合に実現可能です。
ウェブサイトは、このページに含める前にこの入力をサニタイジングすることで、 XSS から自身を保護する必要があります。 CSP は、サニタイジングが失敗した場合でもウェブサイトを保護できる、補完的な保護機能を提供します。
サニタイジングが失敗した場合、様々な形の悪意のあるコードが文書に注入される可能性があります。
悪意のあるリソースへリンクする
<script>タグhtml<script src="https://evil.example.com/hacker.js"></script>インライン JavaScript を含む
<script>タグhtml<script> console.log("ハックされました!");</script>インラインイベントハンドラー
html<img onmouseover="console.log(`ハックされました!`)" />#"#"></iframe>
A string argument to an unsafe API likeeval():
eval("console.log(`ハックされました!`)");CSP は、これらすべてに対する保護を提供できます。CSP を使用すると、次のことが可能になります。
- JavaScript ファイルおよびその他のリソースの許可ソースを定義し、
https://evil.example.comからの読み込みを効果的にブロックします。 - インラインの script タグを無効にします。
- 正しいノンスまたはハッシュが設定されている script タグのみ許可します。
- インラインイベントハンドラーを無効にします。
#"フェッチディレクティブ" >フェッチディレクティブ
フェッチディレクティブは、文書が読み込むことを許可するリソースの特定のカテゴリー(JavaScript、CSS スタイルシート、画像、フォントなど)を指定するために使用されます。
リソースの種類によって、フェッチディレクティブは異なります。例を示します。
script-srcは JavaScript に許可されたソースを設定します。style-srcは CSS スタイルシートに許可されたソースを設定します。img-srcは画像に許可されたソースを設定します。
特別なフェッチディレクティブとして
default-srcがあります。これは、ディレクティブが明示的に掲載されていないすべてのリソースの代替ポリシーを設定します。フェッチディレクティブの完全なセットについては、リファレンス文書を参照してください。
それぞれのフェッチディレクティブは、単一のキーワード
'none'または、空間で区切られた 1 つ以上の「ソース式」として指定します。複数のソース式が掲載されている場合、いずれかのメソッドがリソースを許可している場合、そのリソースは許可されます。例えば、下記の CSP は 2 つのフェッチディレクティブを設定しています。
default-srcには、単一のソース式'self'が指定されています。img-srcには、2 つのソース式'self'およびexample.comが指定されています。
これは次のような効果になります。
- 画像は、文書と同じオリジンであるか、
example.comから読み込まれている必要があります。 - それ以外のすべてのリソースは、文書と同じオリジンである必要があります。
次のいくつかの節では、ソース式を使用してリソースの読み込みを制御するいくつかの方法について説明します。これらは個別に説明していますが、これらの式は一般的に組み合わせることができます。例えば、単一のフェッチディレクティブには、ホスト名だけでなくノンスも含めることができます。
リソースのブロック
リソース型を完全にブロックするには、キーワード
'none'を使用します。例えば、次のディレクティブは、すべての<object>および<embed>リソースをブロックします。httpContent-Security-Policy: object-src 'none''none'は、特定のディレクティブでは他のメソッドと組み合わせることはできません。実際には、'none'の横に他のソース式が指定されている場合、それらは無視されます。ノンス
nonceを使用する方法が、<script>および<style>のリソースの読み込みを制限するための推奨される方法です。ノンスを使用すると、サーバーは HTTP レスポンスごとにランダムな値を生成し、それを
script-srcおよび/またはstyle-srcディレクティブに記載します。httpContent-Security-Policy: script-src 'nonce-416d1177-4d12-4e3b-b7c9-f6c409789fb8'サーバーは、この値を、文書内に組み込む予定のすべての
<script>および/または<style>タグのnonce属性の値として記載します。ブラウザーは 2 つの値を比較し、それらが一致する場合にのみリソースを読み込みます。このアイディアは、攻撃者がページに JavaScript を挿入できたとしても、攻撃者はサーバーが使用するノンスを知らないため、ブラウザーはスクリプトの実行を拒否するというものです。
この手法が機能するには、攻撃者がノンスを推測できないことが必要です。
実際には、これは、ノンスはすべての HTTP レスポンスで異なっており、予測不可能でなければならないということです。
これは、サーバーは毎回新しいノンスを挿入しなければならないため、静的な HTML を提供できないことを意味します。通常、サーバーはテンプレートエンジンを使用してノンスを挿入します。
以下は、これを示すExpress のコードの抜粋です。
jsfunction content(nonce) { return ` <script nonce="${nonce}" src="/main.js"></script> <script nonce="${nonce}">console.log("hello!");</script> <h1>Hello world</h1> `;}app.get("/", (req, res) => { const nonce = crypto.randomUUID(); res.setHeader("Content-Security-Policy", `script-src 'nonce-${nonce}'`); res.send(content(nonce));});リクエストごとに、サーバーは新しいノンスを生成し、それを CSP および返される文書内の
<script>タグに挿入します。サーバーは次のことを行うことに注意してください。- リクエストごとに新しいノンスを生成します。
- 外部スクリプトとインラインスクリプトの両方でノンスを使用することができます。
- 文書内のすべての
<script>タグに同じノンスを使用します。
サーバーは、ノンスを挿入するために何らかのテンプレートを使用し、すべての
<script>タグにノンスを挿入しないことが重要です。そうしないと、サーバーが、攻撃者によって挿入されたスクリプトに誤ってノンスを挿入してしまう可能性があります。ノンスは、
nonce属性を持つ要素、つまり<script>および<style>要素にのみ使用できることに注意してください。ハッシュ
フェッチディレクティブは、その整合性を保証するために、スクリプトのハッシュを使用することもできます。このメソッドを使用すると、サーバーは次のようになります。
- ハッシュ関数 (SHA-256、SHA-384、SHA-512 のいずれか) を使用して、スクリプトのコンテンツのハッシュを計算します。
- 結果のBase64 エンコードを作成します。
- 使用されているハッシュアルゴリズム (
sha256-、sha384-、sha512-のいずれか) を識別する接頭辞を追加します。
次に、その結果をディレクティブに追加します。
httpContent-Security-Policy: script-src 'sha256-cd9827ad...'ブラウザーが文書を受信すると、スクリプトをハッシュ化し、その結果をヘッダーの値と比較し、一致する場合にのみスクリプトを読み込みます。
このメソッドが機能するためには、外部スクリプトにも
integrity属性が含まれている必要があります。以下は、これを示す Express のコードの抜粋です。
jsconst hash1 = "sha256-ex2O7MWOzfczthhKm6azheryNVoERSFrPrdvxRtP8DI=";const hash2 = "sha256-H/eahVJiG1zBXPQyXX0V6oaxkfiBdmanvfG9eZWSuEc=";const csp = `script-src '${hash1}' '${hash2}'`;const content = ` <script src="./main.js" integrity="${hash2}"></script> <script>console.log("hello!");</script> <h1>Hello world</h1> `;app.get("/", (req, res) => { res.setHeader("Content-Security-Policy", csp); res.send(content);});次の点に注意してください。
- 文書内のすべてのスクリプトに個別のハッシュを設定しています。
- 外部スクリプト "main.js" にも
integrity属性を記載し、同じ値を指定しています。 - ノンスを使用する例とは異なり、ハッシュは変化しないため、CSP とコンテンツはどちらも静的であることができます。これにより、ハッシュベースのポリシーは、クライアント側のレンダリングに依存する静的なページやウェブサイトにより適したものになります。
スキームベースのポリシー
フェッチディレクティブは、
https:のようなスキームをリストして、そのスキームを使用して提供されるリソースを許可することができます。例えば、これにより、すべてのリソースの読み込みに HTTPS を要求するポリシーを設定することができます。httpContent-Security-Policy: default-src https:場所ベースのポリシー
フェッチディレクティブは、リソースの場所に基づいてリソースの読み込みを制御できます。
キーワード
'self'は、文書自体と同じオリジンを持つリソースを許可します。httpContent-Security-Policy: img-src 'self'また、ワイルドカードを含む 1 つ以上のホスト名を指定して、それらのホストから提供されるリソースのみを許可することもできます。これは、例えば、信頼できる CDN からコンテンツを提供するために使用することができます。
httpContent-Security-Policy: img-src *.example.org複数の場所を指定することができます。次のディレクティブは、現在の文書と同じ起源の画像、または "example.org" のサブドメインから提供されている画像、あるいは "example.com" から提供されている画像のみを許可します。
httpContent-Security-Policy: img-src 'self' *.example.org example.comインライン JavaScript
CSP に
default-srcまたはscript-srcディレクティブが含まれている場合、それを有効にする追加の措置を講じない限り、インライン JavaScript は実行できません。これには以下が含まれます。ページ内の
<script>要素内に含まれる JavaScripthtml<script> console.log("インラインスクリプトからこんにちは");</script>インラインイベントハンドラー属性での JavaScript
html<img src="x" onerror="console.log('インラインイベントハンドラーからこんにちは')" />#"#"></a>