厳格なコンテンツ セキュリティ ポリシー(CSP)を使用してクロスサイト スクリプティング(XSS)を軽減する

対応ブラウザ

  • Chrome: 52。 <ph type="x-smartling-placeholder">
  • Edge: 79。 <ph type="x-smartling-placeholder">
  • Firefox: 52。 <ph type="x-smartling-placeholder">
  • Safari: 15.4。 <ph type="x-smartling-placeholder">

ソース

クロスサイト スクリプティング(XSS) ウェブアプリに悪意のあるスクリプトを挿入する機能は、 10 年以上にわたり続々と公開されています

コンテンツ セキュリティ ポリシー(CSP) XSS の軽減に役立つ追加のセキュリティ レイヤです。CSP を構成するには Content-Security-Policy HTTP ヘッダーをウェブページに追加し、 そのページでユーザー エージェントが読み込めるリソースを制御します。

このページでは、ノンスまたはハッシュに基づいて CSP を使用して XSS を軽減する方法について説明します。 よく利用されているホスト許可リストベースの CSP ではなく、 ほとんどの構成でバイパスできるため、XSS に公開されません。

重要な用語: ノンスとは 1 回だけ使用する乱数で、特定の値をマークするために使用できます。 <script> タグとして信頼できるものとしてタグ付けしました。

重要な用語: ハッシュ関数は、入力値を変換する数学関数 ハッシュと呼ばれる圧縮された数値に変換します。ハッシュを使用すると (SHA-256 など)を使用して、インラインの <script> タグとして信頼できるものとしてタグ付けしました。

ノンスまたはハッシュに基づくコンテンツ セキュリティ ポリシーは、 厳格な CSP に準拠する必要があります。アプリケーションで厳格な CSP が使用されている場合、 一般的に、インジェクション脆弱性を利用してブラウザを無理やり実行することはできない 悪意のあるスクリプトを悪用できます。これは、厳格な CSP のみが ハッシュされたスクリプト、または正しいノンス値を持つスクリプトが そのため、攻撃者は正しいノンスを知らずにスクリプトを実行できません。 表示されます。

厳格な CSP を使用すべき理由

サイトに script-src www.googleapis.com のような CSP がすでに存在する場合、 クロスサイトには効果がないと考えられますこのタイプの CSP は 許可リストの CSP。カスタマイズには多くのカスタマイズが必要で、 回避されます。

暗号ノンスや暗号ハッシュに基づく厳格な CSP であれば、こうした問題を回避できます。

厳格な CSP 構造

基本的な厳格なコンテンツ セキュリティ ポリシーでは、次のいずれかの HTTP レスポンスが使用されます。 ヘッダー:

ノンスベースの厳格な CSP

Content-Security-Policy:
  script-src 'nonce-{RANDOM}' 'strict-dynamic';
  object-src 'none';
  base-uri 'none';
<ph type="x-smartling-placeholder">
</ph>
ノンスベースの厳格な CSP の仕組み

ハッシュベースの厳格な CSP

Content-Security-Policy:
  script-src 'sha256-{HASHED_INLINE_SCRIPT}' 'strict-dynamic';
  object-src 'none';
  base-uri 'none';

次の特性により、このような CSP は「厳格」になります安全です。

  • ノンス 'nonce-{RANDOM}' またはハッシュ 'sha256-{HASHED_INLINE_SCRIPT}' を使用する サイトのデベロッパーが信頼する <script> タグを示す 表示されます。
  • 'strict-dynamic' を設定する。 ノンスベースまたはハッシュベースの CSP をデプロイ 信頼できるスクリプトが作成したスクリプトを実行できます。また、 は、サードパーティの JavaScript ライブラリとウィジェットのほとんどの使用をブロックします。
  • URL 許可リストに基づいていないため、 一般的な CSP のバイパスをご覧ください。
  • インライン イベント ハンドラや javascript: などの信頼できないインライン スクリプトをブロックします。 URI などです。
  • Flash などの危険なプラグインを無効にするように object-src を制限します。
  • base-uri を制限して、<base> タグの注入をブロックします。これにより 相対 URL から読み込まれたスクリプトの場所を変更できないようにする。
で確認できます。

厳格な CSP の採用

厳格な CSP を導入するには、次のことを行う必要があります。

  1. アプリケーションでノンスベースの CSP とハッシュベースの CSP のどちらを設定するかを決定します。
  2. [厳格な CSP 構造] セクションから CSP をコピーして設定します。 レスポンス ヘッダーとして使用できます。
  3. HTML テンプレートとクライアントサイドのコードをリファクタリングして、 CSP と互換性がありません。
  4. CSP をデプロイします。

Lighthouse を使用できます。 (v7.3.0 以降、フラグ --preset=experimental を使用)ベスト プラクティスの監査 サイトで CSP が実装されているかどうか、実装が XSS に対抗できるほど厳格化されています。

<ph type="x-smartling-placeholder">
</ph> 灯台
  適用モードで CSP が見つからないという警告を報告する。
サイトに CSP がない場合は、Lighthouse にこの警告が表示されます。

ステップ 1: ノンスベースとハッシュベースの CSP のどちらが必要かを判断する

2 種類の厳格な CSP の仕組みは次のとおりです。

ノンスベースの CSP

ノンスベースの CSP では、実行時に乱数を生成し、 ページ内のすべてのスクリプトタグに関連付けます。攻撃者 悪意のあるスクリプトをページに含めたり実行したりすることは、 そのスクリプトの正しい乱数を推測します。この方法は、 実行時にレスポンスのたびに新しく生成されます。

サーバーでレンダリングされる HTML ページにノンスベースの CSP を使用します。これらのページでは レスポンスごとに新しい乱数を作成できます。

ハッシュベースの CSP

ハッシュベースの CSP の場合、すべてのインライン スクリプトタグのハッシュが CSP に追加されます。 スクリプトごとに異なるハッシュがあります。攻撃者が悪意のあるファイルを含めたり スクリプトをページに用意します。スクリプトのハッシュをページの CSP が必要です。

静的に提供される HTML ページや、コンテンツ配信を必要とするページには、ハッシュベースの CSP を使用します。 キャッシュに保存されます。たとえば、単一ページのウェブにハッシュベースの CSP を使用できます。 Angular、React などのフレームワークで構築されたアプリケーション サーバーサイド レンダリングを行わずに静的に配信されます。

ステップ 2: 厳格な CSP を設定してスクリプトを準備する

CSP を設定するには、いくつかのオプションがあります。

  • レポート専用モード(Content-Security-Policy-Report-Only)または適用モード (Content-Security-Policy).レポート専用モードでは、CSP は サイトには何も問題はありませんが ブロックされた可能性のあるコンテンツについても 報告できますローカルに 設定しても、これは問題ではありません。どちらのモードでも、 エラーが表示されます。強制適用モードを使用すると 下書きの CSP でブロックされるリソースを減らします。リソースをブロックすると、 ページが破損しているように見えます。レポート専用モードはプロセスの後半で特に有用 (ステップ 5 を参照)。
  • ヘッダーまたは HTML の <meta> タグ。ローカルで開発する場合は、次のように <meta> タグを使用します。 CSP を調整して、サイトへの影響をすばやく確認するのに便利です。 ただし、次の点に注意してください。 <ph type="x-smartling-placeholder">
      </ph>
    • 後で CSP を本番環境にデプロイするときに、CSP を 使用できます。
    • CSP をレポート専用モードに設定する場合は、 CSP メタタグはレポート専用モードをサポートしていないためです。

オプション A: ノンスベースの CSP

次の Content-Security-Policy HTTP レスポンスを設定します。 ヘッダーがあります。

Content-Security-Policy:
  script-src 'nonce-{RANDOM}' 'strict-dynamic';
  object-src 'none';
  base-uri 'none';
<ph type="x-smartling-placeholder">

CSP のノンスを生成する

ノンスとは、ページの読み込みごとに 1 回だけ使用される乱数です。ノンスベースの CSP は、攻撃者がノンス値を推測できない場合にのみ、XSS を軽減できます。 CSP nonce は以下である必要があります。

  • 暗号的に強いランダム値(理想的には 128 ビット以上の長さ)
  • 回答ごとに新しく生成
  • Base64 エンコード

サーバーサイド フレームワークで CSP のノンスを追加する方法の例を以下に示します。

const app = express();

app.get('/', function(request, response) {
  // Generate a new random nonce value for every response.
  const nonce = crypto.randomBytes(16).toString("base64");

  // Set the strict nonce-based CSP response header
  const csp = `script-src 'nonce-${nonce}' 'strict-dynamic'; object-src 'none'; base-uri 'none';`;
  response.set("Content-Security-Policy", csp);

  // Every <script> tag in your application should set the `nonce` attribute to this value.
  response.render(template, { nonce: nonce });
});

<script> 要素に nonce 属性を追加する

ノンスベースの CSP では、すべての <script> 要素が ランダムなノンスに一致する nonce 属性がある 値のみがサポートされています。すべてのスクリプトに同じ ノンス。まず、これらの属性をすべてのスクリプトに追加して、 CSP が許可します。

オプション B: ハッシュベースの CSP レスポンス ヘッダー

次の Content-Security-Policy HTTP レスポンスを設定します。 ヘッダーがあります。

Content-Security-Policy:
  script-src 'sha256-{HASHED_INLINE_SCRIPT}' 'strict-dynamic';
  object-src 'none';
  base-uri 'none';

複数のインライン スクリプトの場合、構文は次のとおりです。 'sha256-{HASHED_INLINE_SCRIPT_1}' 'sha256-{HASHED_INLINE_SCRIPT_2}'

<ph type="x-smartling-placeholder">

スクリプトの動的な読み込み

CSP ハッシュはインライン スクリプトでのみサポートされているため、 インライン スクリプトを使用して、すべてのサードパーティ スクリプトを動的に読み込む必要があります。 ソース スクリプトのハッシュは、ブラウザ間で十分にサポートされていません

<ph type="x-smartling-placeholder">
</ph>
スクリプトをインライン化する方法の例
CSP で許可
<script>
  var scripts = [ 'https://example.org/foo.js', 'https://example.org/bar.js'];

  scripts.forEach(function(scriptUrl) {
    var s = document.createElement('script');
    s.src = scriptUrl;
    s.async = false; // to preserve execution order
    document.head.appendChild(s);
  });
</script>
<ph type="x-smartling-placeholder"></ph> このスクリプトを実行するには、インライン スクリプトのハッシュを計算する必要があります。 それを CSP レスポンス ヘッダーに追加し、{HASHED_INLINE_SCRIPT} を 使用します。ハッシュの量を減らすために、インラインで スクリプトを 1 つのスクリプトにまとめます。実際の動作を確認するには、こちらの そのコード
CSP によるブロック
<script src="https://example.org/foo.js"></script>
<script src="https://example.org/bar.js"></script>
<ph type="x-smartling-placeholder"></ph> CSP は、インライン スクリプトのみをハッシュ化できるため、これらのスクリプトをブロックします。
<ph type="x-smartling-placeholder">

スクリプト読み込みに関する考慮事項

このインライン スクリプトの例では、s.async = false を追加して、 その foobar より前に実行されること。これには、 bar が最初に読み込まれます。このスニペットでは、s.async = false は、スクリプトの読み込み中にパーサーをブロックしません。これは、スクリプトが 動的に追加されています。パーサーはスクリプトの実行中にのみ停止します。これは、 async スクリプトの場合は次のようになります。しかしこのスニペットでは 次の点にご注意ください。

  • ドキュメントの処理が完了する前に、スクリプトの 1 つまたは両方が実行されることがあります ダウンロードします。それまでにドキュメントを準備しておきたい場合は、 DOMContentLoaded イベントを待ってから、 スクリプトを追加します。なんらかの理由でパフォーマンスの問題が生じている場合は、 スクリプトのダウンロードが早期に開始されない場合は、ページの早い段階でプリロード タグを使用してください。
  • defer = true は何も実行しません。必要な場合は 必要に応じてスクリプトを手動で実行してください。

ステップ 3: HTML テンプレートとクライアントサイドのコードをリファクタリングする

インライン イベント ハンドラ(onclick="…"onerror="…" など)と JavaScript URI (<a href="javascript:…">)を使用してスクリプトを実行できます。つまり XSS バグを発見した攻撃者は、この種の HTML を挿入し、悪意のある 使用できます。ノンスベースまたはハッシュベースの CSP では、このようなマークアップの使用が禁止されています。 サイトでこれらのパターンのいずれかを使用している場合は、より安全なものにリファクタリングする必要があります。 できます。

前の手順で CSP を有効にした場合は、CSP 違反を 互換性のないパターンが CSP によってブロックされるたびに、コンソールに表示されます。

<ph type="x-smartling-placeholder">
</ph> Chrome デベロッパー コンソールの CSP 違反レポート
ブロックされたコードのコンソール エラー。

ほとんどの場合、次のように簡単に修正できます。

インライン イベント ハンドラをリファクタリングする

CSP で許可
<span id="things">A thing.</span>
<script nonce="${nonce}">
  document.getElementById('things').addEventListener('click', doThings);
</script>
<ph type="x-smartling-placeholder"></ph> CSP では、JavaScript を使用して登録されるイベント ハンドラが許可されます。
CSP によるブロック
<span onclick="doThings();">A thing.</span>
<ph type="x-smartling-placeholder"></ph> CSP はインライン イベント ハンドラをブロックします。

javascript: URI をリファクタリングする

CSP で許可
<a id="foo">foo</a>
<script nonce="${nonce}">
  document.getElementById('foo').addEventListener('click', linkClicked);
</script>
<ph type="x-smartling-placeholder"></ph> CSP では、JavaScript を使用して登録されるイベント ハンドラが許可されます。
CSP によるブロック
<a href="javascript:linkClicked()">foo</a>
<ph type="x-smartling-placeholder"></ph> CSP は JavaScript: URI をブロックします。

JavaScript から eval() を削除する

アプリケーションで eval() を使用して JSON 文字列のシリアル化を JS に変換する場合 そのようなインスタンスを JSON.parse() にリファクタリングする必要があります。 より高速

eval() の使用をすべて削除できない場合でも、厳格なノンスベースの設定を ただし、'unsafe-eval' CSP キーワードを使用する必要があり、 ポリシーでは安全性が若干劣ります。

このようなリファクタリングの例については、この厳格な CSP をご覧ください。 codelab:

ステップ 4(省略可): フォールバックを追加して古いバージョンのブラウザをサポートする

対応ブラウザ

  • Chrome: 52。 <ph type="x-smartling-placeholder">
  • Edge: 79。 <ph type="x-smartling-placeholder">
  • Firefox: 52。 <ph type="x-smartling-placeholder">
  • Safari: 15.4。 <ph type="x-smartling-placeholder">

ソース

古いバージョンのブラウザをサポートする場合:

  • strict-dynamic を使用するには、以前の関数のフォールバックとして https: を追加する必要があります。 Safari の新しいバージョンです。これを行うと、次のようになります。 <ph type="x-smartling-placeholder">
      </ph>
    • strict-dynamic をサポートするすべてのブラウザでは、https: フォールバックは無視されます。 それによってポリシーの強度が低下することはありません。
    • 古いブラウザでは、外部ソースのスクリプトは、そのスクリプトが HTTPS オリジンを指定します。厳格な CSP よりも安全性は劣りますが、 これにより、javascript: URI のインジェクションなどの一般的な XSS の原因が防止されます。
  • 古いバージョン(4 年以上)のブラウザとの互換性を確保するために、 フォールバックとして unsafe-inline。最近のブラウザでは unsafe-inline が無視される CSP nonce または hash が存在する場合)。
で確認できます。
Content-Security-Policy:
  script-src 'nonce-{random}' 'strict-dynamic' https: 'unsafe-inline';
  object-src 'none';
  base-uri 'none';

ステップ 5: CSP をデプロイする

CSP が正規のスクリプトをブロックしていないことを確認したら、 ローカル開発環境でデプロイする場合、CSP をステージング環境にデプロイしてから、 本番環境:

  1. (省略可)CSP をレポート専用モードでデプロイするには、 Content-Security-Policy-Report-Only ヘッダー。レポート専用モードは 新しい CSP など、互換性を破る可能性のある変更を本番環境でテストしてから、 CSP 制限の適用を開始しますレポート専用モードでは、CSP は ブラウザがコンソール エラーを生成する お客様の CSP と互換性のないパターンに遭遇した場合、 エンドユーザーにとって何が問題になるかを把握できます詳細情報 Reporting API をご覧ください。
  2. CSP がエンドユーザーのためにサイトを壊さないと確信したら、 Content-Security-Policy レスポンス ヘッダーを使用して CSP をデプロイします。水 CSP の設定には HTTP ヘッダー サーバーサイドの使用が推奨されます。 <meta> タグよりも安全です。この手順を完了すると、CSP が アプリを XSS から保護する方法を学びました
で確認できます。

制限事項

一般的に、厳格な CSP にすると、セキュリティが強力に強化され、セキュリティ XSS を軽減できます。ほとんどの場合、CSP は javascript: URI などの危険なパターンを拒否します。データ型によっては 使用している CSP(ノンス、ハッシュ、'strict-dynamic' の有無にかかわらず) CSP でもアプリを保護できないケースは次のとおりです。

  • スクリプトをノンスするが、body または その <script> 要素の src パラメータ。
  • 動的に作成されたスクリプトの場所へのインジェクションの有無 (document.createElement('script'))(ライブラリ関数内を含む) 引数の値に基づいて script 個の DOM ノードを作成します。この には、jQuery の .html() などの一般的な API のほか、.get() および jQuery の .post() <3.0.
  • 古い AngularJS アプリケーションでテンプレート インジェクションが行われるかどうか。攻撃者 AngularJS のテンプレートに挿入できる API を 任意の JavaScript を実行できます
  • ポリシーに 'unsafe-eval'eval() へのインジェクション、 setTimeout() などのめったに使用されない API。

デベロッパーやセキュリティ エンジニアは、 コードレビューやセキュリティ監査におけるパターンを学習します。詳しくは、 これらのケースについては、コンテンツ セキュリティ ポリシー: 強化と緩和策間の成功の度合いをご覧ください。

関連情報