対応ブラウザ
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <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">
ハッシュベースの厳格な 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 を導入するには、次のことを行う必要があります。
- アプリケーションでノンスベースの CSP とハッシュベースの CSP のどちらを設定するかを決定します。
- [厳格な CSP 構造] セクションから CSP をコピーして設定します。 レスポンス ヘッダーとして使用できます。
- HTML テンプレートとクライアントサイドのコードをリファクタリングして、 CSP と互換性がありません。
- CSP をデプロイします。
Lighthouse を使用できます。
(v7.3.0 以降、フラグ --preset=experimental
を使用)ベスト プラクティスの監査
サイトで CSP が実装されているかどうか、実装が
XSS に対抗できるほど厳格化されています。
ステップ 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 メタタグはレポート専用モードをサポートしていないためです。
次の 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 のノンスを追加する方法の例を以下に示します。
- Django(Python)
- Express(JavaScript):
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 が許可します。
次の 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}'
。
スクリプトの動的な読み込み
CSP ハッシュはインライン スクリプトでのみサポートされているため、 インライン スクリプトを使用して、すべてのサードパーティ スクリプトを動的に読み込む必要があります。 ソース スクリプトのハッシュは、ブラウザ間で十分にサポートされていません。
<ph type="x-smartling-placeholder"><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">
<script src="https://example.org/foo.js"></script> <script src="https://example.org/bar.js"></script><ph type="x-smartling-placeholder">
スクリプト読み込みに関する考慮事項
このインライン スクリプトの例では、s.async = false
を追加して、
その foo
が bar
より前に実行されること。これには、
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">ほとんどの場合、次のように簡単に修正できます。
インライン イベント ハンドラをリファクタリングする
<span id="things">A thing.</span> <script nonce="${nonce}"> document.getElementById('things').addEventListener('click', doThings); </script><ph type="x-smartling-placeholder">
<span onclick="doThings();">A thing.</span><ph type="x-smartling-placeholder">
javascript:
URI をリファクタリングする
<a id="foo">foo</a> <script nonce="${nonce}"> document.getElementById('foo').addEventListener('click', linkClicked); </script><ph type="x-smartling-placeholder">
<a href="javascript:linkClicked()">foo</a><ph type="x-smartling-placeholder">
JavaScript から eval()
を削除する
アプリケーションで eval()
を使用して JSON 文字列のシリアル化を JS に変換する場合
そのようなインスタンスを JSON.parse()
にリファクタリングする必要があります。
より高速。
eval()
の使用をすべて削除できない場合でも、厳格なノンスベースの設定を
ただし、'unsafe-eval'
CSP キーワードを使用する必要があり、
ポリシーでは安全性が若干劣ります。
このようなリファクタリングの例については、この厳格な CSP をご覧ください。 codelab:
ステップ 4(省略可): フォールバックを追加して古いバージョンのブラウザをサポートする
対応ブラウザ
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <ph type="x-smartling-placeholder">
- <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 をステージング環境にデプロイしてから、 本番環境:
- (省略可)CSP をレポート専用モードでデプロイするには、
Content-Security-Policy-Report-Only
ヘッダー。レポート専用モードは 新しい CSP など、互換性を破る可能性のある変更を本番環境でテストしてから、 CSP 制限の適用を開始しますレポート専用モードでは、CSP は ブラウザがコンソール エラーを生成する お客様の CSP と互換性のないパターンに遭遇した場合、 エンドユーザーにとって何が問題になるかを把握できます詳細情報 Reporting API をご覧ください。 - 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。
デベロッパーやセキュリティ エンジニアは、 コードレビューやセキュリティ監査におけるパターンを学習します。詳しくは、 これらのケースについては、コンテンツ セキュリティ ポリシー: 強化と緩和策間の成功の度合いをご覧ください。