次の方法で共有


コンテンツ セキュリティ ポリシー (CSP) を使用して実行できるリソースを制御する

拡張機能で実行できるコンテンツを制御するには、拡張機能の manifest.json ファイルで、次の構文に従って、 content_security_policy キーとそのポリシー文字列値を使用します。

{
    ...,
    "content_security_policy": "[policy string]"
    ...
}

たとえば、「既定のポリシー制限」で後述するように、既定のコンテンツ セキュリティ ポリシーを次に示 します

{
    ...,
    "content_security_policy": "script-src 'self'; object-src 'self'; worker-src 'self'"
    ...
}

潜在的なクロスサイト スクリプティングの問題の大規模なクラスを軽減するために、Microsoft Edge 拡張機能システムにはコンテンツ セキュリティ ポリシー (CSP) が組み込まれています。 CSP では、拡張機能のセキュリティを既定で強化するいくつかの厳格なポリシーが導入されており、拡張機能とアプリケーションによって読み込まれて実行できるコンテンツの種類を管理するルールを作成して適用する機能が提供されます。

一般に、CSP は、拡張機能によって読み込まれた、または実行されるリソースのブロック/許可リストメカニズムとして機能します。 拡張機能に適切なポリシーを定義すると、拡張機能で必要なリソースを慎重に検討し、拡張機能がアクセスできる唯一のリソースであることをブラウザーに確認することができます。 ポリシーは、拡張要求のホストアクセス許可以上のセキュリティを提供します。これらは、代替ではなく、追加の保護レイヤーです。

一方、Web ページでは、このようなポリシーは HTTP ヘッダーまたは meta 要素を介して定義されます。 ただし、Microsoft Edge 拡張機能システム内では、HTTP ヘッダーまたは meta 要素は適切なメカニズムではありません。

参照:

既定のポリシー制限

manifest_versionを定義しないパッケージには、既定のコンテンツ セキュリティ ポリシーがありません。

manifest_versionを使用するパッケージには、次の既定のコンテンツ セキュリティ ポリシーがあります。

script-src 'self'; object-src 'self'; worker-src 'self'

このポリシーでは、次の 3 つの方法で拡張機能とアプリケーションを制限することでセキュリティが追加されます。

次のようなコードは機能しません。

alert(eval("foo.bar.baz"));
window.setTimeout("alert('hi')", 10);
window.setInterval("alert('hi')", 10);
new Function("return foo.bar.baz");

このような JavaScript の文字列の評価は、一般的な XSS 攻撃ベクトルです。 代わりに、次のようなコードを記述する必要があります。

alert(foo && foo.bar && foo.bar.baz);
window.setTimeout(function() { alert('hi'); }, 10);
window.setInterval(function() { alert('hi'); }, 10);
function() { return foo && foo.bar && foo.bar.baz };

インライン JavaScript が実行されない

インライン JavaScript は実行されません。 この制限では、インライン <script> ブロックとインライン イベント ハンドラー ( <button onclick="..."> など) の両方が禁止されます。

最初の制限は、悪意のあるサード パーティによって提供されたスクリプトを誤って実行できないようにすることで、クロスサイト スクリプティング攻撃の巨大なクラスを一掃します。 ただし、コンテンツと動作をクリーン分離してコードを記述する必要があります。 たとえば、これを明確にする場合があります。 ブラウザー アクション ポップアップを、次の内容を含む単一の pop-up.html として記述できます。

<!doctype html>
<html>
    <head>
        <title>My Awesome Pop-up!</title>
        <script>
            function awesome() {
                // do something awesome!
            }

            function totallyAwesome() {
                // do something TOTALLY awesome!
            }

            function clickHandler(element) {
                setTimeout("awesome(); totallyAwesome()", 1000);
            }

            function main() {
                // Initialization work goes here.
            }
        </script>
    </head>
    <body onload="main();">
        <button onclick="clickHandler(this)">
            Click for awesomeness!
        </button>
    </body>
</html>

ただし、この作業を想定した方法で行うには、次の 3 つのことを変更する必要があります。

  • clickHandler定義は、外部 JavaScript ファイルに移動する必要があります (popup.jsが適切なターゲットである可能性があります)。

  • インライン イベント ハンドラー定義は、 addEventListener の観点から書き換え、 popup.jsに抽出する必要があります。 現在、 <body onload="main();">などのコードを使用してプログラムを開始している場合は、要件に応じて、ドキュメントの DOMContentLoaded イベント、またはウィンドウの load イベントにフックして置き換えることを検討してください。 一般に、より迅速にトリガーされるため、前者を使用します。

  • setTimeout呼び出しは、実行のために文字列"awesome(); totallyAwesome()"を JavaScript に変換しないように書き換える必要があります。

これらの変更は、次のようになります。

function awesome() {
    // Do something awesome!
}

function totallyAwesome() {
    // do something TOTALLY awesome!
}

function awesomeTask() {
    awesome();
    totallyAwesome();
}

function clickHandler(e) {
    setTimeout(awesomeTask, 1000);
}

function main() {
    // Initialization work goes here.
}

// Add event listeners once the DOM has fully loaded by listening for the
// `DOMContentLoaded` event on the document, and adding your listeners to
// specific elements when it triggers.
document.addEventListener('DOMContentLoaded', function () {
    document.querySelector('button').addEventListener('click', clickHandler);
    main();
});
<!doctype html>
<html>
    <head>
        <title>My Awesome Pop-up!</title>
        <script src="popup.js"></script>
    </head>
    <body>
        <button>Click for awesomeness!</button>
    </body>
</html>

ローカル スクリプトとオブジェクト リソースのみが読み込まれます

スクリプト リソースとオブジェクト リソースは、Web からではなく、拡張機能パッケージからのみ読み込むことができます。 これにより、拡張機能が明示的に承認したコードのみを実行し、アクティブなネットワーク攻撃者がリソースの要求を悪意を持ってリダイレクトできないようにします。

外部 CDN からの jQuery (またはその他のライブラリ) の読み込みに依存するコードを記述する代わりに、拡張機能パッケージに特定のバージョンの jQuery を含めることを検討してください。 つまり、次の代わりに、

<!doctype html>
<html>
    <head>
        <title>My Awesome Pop-up!</title>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
    </head>
    <body>
        <button>Click for awesomeness!</button>
    </body>
</html>

代わりに、次の方法を使用します。 ファイルをダウンロードし、パッケージに含め、次のように書き込みます。

<!doctype html>
<html>
    <head>
        <title>My Awesome Pop-up!</title>
        <script src="jquery.min.js"></script>
    </head>
    <body>
        <button>Click for awesomeness!</button>
    </body>
</html>

既定のポリシーを緩和する

次の種類のスクリプトの実行を許可できます。

詳細は以下のとおりです。

インライン スクリプト

インライン スクリプトは、ポリシーでソース コードの base64 でエンコードされたハッシュを指定することで許可できます。 このハッシュには、使用されるハッシュ アルゴリズム (sha256、sha384、または sha512) のプレフィックスを付ける必要があります。 例については、<script> 要素の W3C > Hash の使用法に関するページを参照してください。

リモート スクリプト

一部の外部 JavaScript またはオブジェクト リソースが必要な場合は、スクリプトを受け入れる必要がある安全な配信元を許可することで、ポリシーを制限された範囲で緩和できます。 拡張機能の昇格されたアクセス許可で読み込まれたランタイム リソースが想定どおりのリソースであり、アクティブなネットワーク攻撃者に置き換えられていないことを確認します。 中間者攻撃は、HTTP に対する単純な攻撃と検出不能の両方であるため、これらの配信元は受け入れられません。

現在、 blobfilesystemhttpsextensionのスキームを持つ許可リストの配信元を許可できます。 配信元のホスト部分は、 https スキームと extension スキームに明示的に指定する必要があります。 https:、 https://*https://*.com などの汎用ワイルドカードは使用できません。 https://*.example.com などのサブドメイン ワイルドカードは許可されます。 パブリック サフィックスの一覧のドメインは、汎用の最上位ドメインとしても表示されます。 これらのドメインからリソースを読み込むには、サブドメインを明示的に一覧表示する必要があります。 たとえば、 https://*.cloudfront.net は無効ですが、 https://XXXX.cloudfront.nethttps://*.XXXX.cloudfront.netallowlistedできます。

開発を容易にするために、ローカル コンピューター上のサーバーから HTTP 経由で読み込まれたリソースを allowlistedできます。 http://127.0.0.1またはhttp://localhostのいずれかのポートで、許可リスト スクリプトとオブジェクト ソースを使用できます。

HTTP 経由で読み込まれたリソースに対する制限は、直接実行されるリソースにのみ適用されます。 たとえば、任意の配信元に XMLHTTPRequest 接続を行うには、引き続き無料です。既定のポリシーでは、 connect-src やその他の CSP ディレクティブは制限されません。

スクリプト リソースを HTTPS 経由で example.com から読み込める緩和されたポリシー定義は、次のようになります。

"content_security_policy": "script-src 'self' https://example.com; object-src 'self'"

script-srcobject-srcの両方がポリシーによって定義されます。 Microsoft Edge では、これらの各値を (少なくとも) 'self' に制限しないポリシーは受け入れられません。

評価された JavaScript

eval()に対するポリシーと、setTimeout(String)setInterval(String)new Function(String)などの関連する機能に対するポリシーは、ポリシーにunsafe-evalを追加することで緩和できます。

"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"

ただし、ポリシーの緩和は避ける必要があります。 これらの種類の関数は、悪名高い XSS 攻撃ベクトルです。

既定のポリシーを引き締める

このポリシーは、利便性を犠牲にして、セキュリティを強化するために、拡張機能で許可されている範囲を問わず厳格化できます。 拡張機能が関連付けられている拡張機能パッケージから任意の種類 (イメージなど) のリソースのみを読み込みることができるように指定するには、たとえば、 default-src 'self' のポリシーが適切な場合があります。

コンテンツ スクリプト

説明中のポリシーは、拡張機能のバックグラウンド ページとイベント ページに適用されます。 コンテンツ スクリプトが拡張機能のコンテンツ スクリプトにどのように適用されるかは、より複雑です。

一般に、コンテンツ スクリプトは拡張機能の CSP の対象ではありません。 コンテンツ スクリプトは HTML ではないため、このメインの影響は、拡張機能の CSP がunsafe-evalを指定していない場合でも、evalを使用できることです。ただし、これは推奨されません。 さらに、ページの CSP はコンテンツ スクリプトには適用されません。 より複雑なタグ <script> 、コンテンツ スクリプトによって作成され、実行されているページの DOM に配置されます。 これらは、今後 DOM 挿入スクリプトとして参照されます。

DOM によって挿入されたスクリプトは、予期したとおりにページに挿入された直後に実行されます。 簡単な例として、次のコードを含むコンテンツ スクリプトを想像してください。

document.write("<script>alert(1);</script>");

このコンテンツ スクリプトにより、document.write()の直後にalertが発生します。 これは ページが指定するポリシーに関係なく実行されます。 ただし、DOM が挿入したスクリプト内と、挿入時にすぐに実行されないスクリプトの両方で、動作がより複雑になります。

拡張機能が、 script-src 'self'を指定する関連付けられた CSP を提供するページで実行されていることを想像してください。 次に、コンテンツ スクリプトで次のコードが実行されるとします。

document.write("<button onclick='alert(1);'>click me</button>'");

ユーザーがそのボタンをクリックした場合、 onclick スクリプトは実行されません。 これは、スクリプトがすぐに実行されず、 click イベントが発生するまで解釈されないコードはコンテンツ スクリプトの一部とは見なされないため、ページの CSP (拡張機能ではなく) によって動作が制限されるためです。 また、その CSP では unsafe-inlineが指定されていないため、インライン イベント ハンドラーはブロックされます。

この場合、目的の動作を実装する正しい方法は、次のように、コンテンツ スクリプトから onclick ハンドラーを関数として追加することです。

document.write("<button id='mybutton'>click me</button>'");
var button = document.getElementById('mybutton');
button.onclick = function() {
      alert(1);
};

コンテンツ スクリプトで次を実行すると、もう 1 つの同様の問題が発生します。

var script = document.createElement('script');
script.innerHTML = 'alert(1);'
document.getElementById('body').appendChild(script);

この場合、スクリプトが実行され、アラートが表示されます。 ただし、次の場合を考えてみましょう。

var script = document.createElement('script');
script.innerHTML = 'eval("alert(1);")';
=document.getElementById('body').appendChild(script);

初期スクリプトの実行中、 eval の呼び出しはブロックされます。 つまり、初期スクリプト ランタイムは許可されますが、スクリプト内の動作はページの CSP によって規制されます。 したがって、拡張機能で DOM 挿入スクリプトを記述する方法によっては、ページの CSP に対する変更が拡張機能の動作に影響する可能性があります。

コンテンツ スクリプトはページの CSP の影響を受けないため、DOM によって挿入されたスクリプトではなく、拡張機能のできるだけ多くの動作をコンテンツ スクリプトに配置する大きな理由です。

関連項目

注:

このページの一部は、 Google によって 作成および共有され、 クリエイティブ・コモンズ属性 4.0 国際ライセンスに記載されている条件に従って使用される作業に基づく変更です。 元のページはこちらにあります。

クリエイティブ・コモンズ・ライセンス この作品は 、クリエイティブ・コモンズ属性4.0国際ライセンスに基づきライセンスされています