CSP の XSS 攻撃に対する効果を確認する

コンテンツ セキュリティ ポリシー(CSP)は、ページに読み込まれるすべてのコンテンツがサイト所有者によって信頼されていることを確認するのに役立ちます。CSP は、攻撃者によって挿入された安全でないスクリプトをブロックできるため、クロスサイト スクリプティング(XSS)攻撃を軽減できます。ただし、CSP が十分に厳格でない場合、簡単にバイパスできます。詳しくは、厳格なコンテンツ セキュリティ ポリシー(CSP)でクロスサイト スクリプティング(XSS)を軽減するをご覧ください。Lighthouse では、メイン ドキュメントで適用されている CSP を収集し、回避できる場合は CSP Evaluator から問題を報告します。

<ph type="x-smartling-placeholder">
</ph> 適用モードの CSP が見つからないという警告が Lighthouse に表示される。
適用モードの CSP が見つからないという警告が Lighthouse レポートに表示される

バイパス不可能な CSP に必要なプラクティス

以下のプラクティスを実装して、CSP がバイパスされないようにします。CSP が回避できる場合は、重大度が「高」の警告が表示されます。

CSP が XSS をターゲットにしている

XSS をターゲットとするには、CSP に script-srcobject-srcbase-uri ディレクティブを含める必要があります。また、CSP では構文エラーがあってはなりません。

script-srcobject-src は、それぞれ安全でないスクリプトと安全でないプラグインからページを保護します。また、default-src を使用すると、script-srcobject-src などの多くのディレクティブの代わりに、広範なポリシーを構成できます。

base-uri は、すべての相対 URL(スクリプトなど)を攻撃者がコントロールするドメインにリダイレクトするために使用できる未承認の <base> タグの挿入を防ぎます。

CSP はノンスまたはハッシュを使用して許可リストのバイパスを回避

script-src の許可リストを設定する CSP は、信頼できるドメインからのすべてのレスポンスは安全であり、スクリプトとして実行できるという前提に基づいています。ただし、この前提は最新のアプリケーションには当てはまりません。JSONP インターフェースの公開や AngularJS ライブラリのコピーのホスティングなど、一般的な無害なパターンにより、攻撃者は CSP の制限を回避することができます。

実際には、アプリケーション作成者からは自明ではないかもしれませんが、script-src 許可リストの大部分は、攻撃者によって XSS バグによって回避される可能性があり、スクリプト インジェクションに対する保護がほとんどありません。一方、ノンスベースとハッシュベースのアプローチではこうした問題はなく、より安全なポリシーの導入と維持が容易になります。

たとえば、次のコードは、信頼できるドメインでホストされている JSONP エンドポイントを使用して、攻撃者が制御するスクリプトを挿入します。

CSP:

script-src https://trusted.example.com

HTML:

<script src="https://trusted.example.com/path/jsonp?callback=alert(document.domain)//"></script>

バイパスを回避するために、CSP はノンスまたはハッシュを使用してスクリプトを個別に許可し、「strict-dynamic」を使用する必要があります。おすすめします。

安全な CSP に関するその他の推奨事項

セキュリティと互換性を高めるために、次のプラクティスを実装してください。CSP がいずれの推奨事項にも従わない場合、Lighthouse では重大度が「中」の警告が表示されます。

CSP レポートを構成する

報告先を設定すると、不具合がないかモニタリングできます。report-uri ディレクティブまたは report-to ディレクティブを使用して、レポート先を設定できます。report-to は現在のところ、すべての最新ブラウザでサポートされているわけではないため、両方を使用するか、report-uri のみを使用することをおすすめします。

CSP に違反するコンテンツがある場合、ブラウザは構成された宛先にレポートを送信します。これらのレポートを処理するアプリケーションがこの宛先に構成されていることを確認してください。

HTTP ヘッダーで CSP を定義する

CSP は、次のようにメタタグで定義できます。

<meta http-equiv="Content-Security-Policy" content="script-src 'none'">

ただし、可能であれば、HTTP レスポンス ヘッダーで CSP を定義する必要があります。メタタグの前に挿入すると、CSP がバイパスされます。また、frame-ancestorssandbox、レポートはメタタグ CSP ではサポートされていません。

CSP の下位互換性を確保する

すべてのブラウザが CSP nonce/hash をサポートしているわけではないため、ポリシーに準拠していないブラウザのフォールバックとして unsafe-inline を追加することをおすすめします。ブラウザがノンスまたはハッシュをサポートしていない場合、unsafe-inline は無視されます。

同様に、strict-dynamic はすべてのブラウザでサポートされているわけではありません。ポリシーに準拠していないブラウザのフォールバックとして許可リストを設定することをおすすめします。strict-dynamic をサポートするブラウザでは、許可リストは無視されます。

厳格な CSP の策定方法

ノンスベースのポリシーで厳格な CSP を使用する例を以下に示します。

CSP:

script-src 'nonce-random123' 'strict-dynamic' 'unsafe-inline' https:;
object-src 'none';
base-uri 'none';
report-uri https://reporting.example.com;

HTML:

<script nonce="random123" src="https://trusted.example.com/trusted_script.js"></script>

random123 は、ページが読み込まれるたびにサーバーサイドで生成される base64 文字列です。ノンスと strict-dynamic があるため、最新のブラウザでは unsafe-inlinehttps: は無視されます。厳格な CSP の採用について詳しくは、Strict CSP ガイドをご覧ください。

Lighthouse と CSP Evaluator を使用して、CSP の潜在的なバイパスをチェックできます。既存のページが破損するリスクを負うことなく新しい CSP をテストする場合は、ヘッダー名として Content-Security-Policy-Report-Only を使用して、レポート専用モードで CSP を定義します。これにより、report-toreport-uri で構成したレポート宛先に CSP 違反が送信されますが、CSP が実際に適用されることはありません。