コンテンツ スクリプト

コンテンツ スクリプトは、ウェブページのコンテキストで実行されるファイルです。標準のドキュメント オブジェクト モデル(DOM)により、ブラウザがアクセスしたウェブページの詳細を読み取って、 親拡張機能に情報が渡されます。

コンテンツ スクリプトの機能を理解する

コンテンツ スクリプトは、次の拡張機能 API に直接アクセスできます。

コンテンツ スクリプトは他の API に直接アクセスすることはできません。ただし、拡張機能の他の部分とメッセージを交換することで、間接的にファイルにアクセスできます。

コンテンツ スクリプトから拡張機能内の他のファイルにアクセスすることもできます。 fetch() などの API。そのためには、これらの変数を ウェブアクセス可能なリソース。なお、こうするとリソースが 同じサイト上で実行されるファーストパーティまたはサードパーティのスクリプト。

隔離された環境で作業する

コンテンツのスクリプトは隔離された世界で暮らしているため、コンテンツ スクリプトがコンテンツに変更を加えることができる ページや他の拡張機能と競合しない JavaScript 環境で、コンテンツスクリプト。

拡張機能は、次の例のようなコードを含むウェブページで実行できます。

webPage.html

<html>
  <button id="mybutton">click me</button>
  <script>
    var greeting = "hello, ";
    var button = document.getElementById("mybutton");
    button.person_name = "Bob";
    button.addEventListener(
        "click", () => alert(greeting + button.person_name + "."), false);
  </script>
</html>

この拡張機能では、 スクリプトの挿入セクション。

content-script.js

var greeting = "hola, ";
var button = document.getElementById("mybutton");
button.person_name = "Roberto";
button.addEventListener(
    "click", () => alert(greeting + button.person_name + "."), false);

この変更により、ボタンをクリックすると両方のアラートが順番に表示されます。

スクリプトの挿入

コンテンツ スクリプトは静的に宣言宣言可能 動的プログラムによる挿入があります。

静的宣言を使用して挿入する

自動的に設定されるスクリプトについては、manifest.json で静的コンテンツ スクリプト宣言を使用します。 既知のページセットで実行されるか

静的に宣言されたスクリプトは、マニフェストの "content_scripts" キーで登録されます。 JavaScript ファイル、CSS ファイル、またはその両方を含めることができます。すべての自動実行コンテンツ スクリプトは、 一致パターン

manifest.json

{
 "name": "My extension",
 ...
 "content_scripts": [
   {
     "matches": ["https://*.nytimes.com/*"],
     "css": ["my-styles.css"],
     "js": ["content-script.js"]
   }
 ],
 ...
}

名前 説明
matches array of strings 必須。このコンテンツ スクリプトを挿入するページを指定します。これらの文字列の構文の詳細については、一致パターンをご覧ください。 および一致パターンと glob を参照して、除外する方法 できます。
css array of strings 省略可。一致するページに挿入される CSS ファイルのリスト。これらは DOM が構築または表示される前に、この配列に出現する順序で挿入される 表示されます。
js 文字列の配列 省略可。一致するページに挿入される JavaScript ファイルのリスト。ファイル この配列に出現する順序で挿入されます。このリストの各文字列には、 拡張機能のルート ディレクトリにあるリソースの相対パス。先頭のスラッシュ(`/`)は、 自動的にカットされます。
run_at RunAt 省略可。スクリプトをページに挿入するタイミングを指定します。デフォルトは document_idle
match_about_blank ブール値 省略可。スクリプトを about:blank フレームに挿入するかどうか 親フレームまたはオープナー フレームが、 matches。デフォルトは false です。
match_origin_as_fallback ブール値 省略可。変更前のフレームにスクリプトを注入するかどうか 一致するオリジンによって作成されますが、その URL またはオリジンは直接 照合されます。これには、 about:data:blob:filesystem:。関連項目 関連フレームへの挿入
world ExecutionWorld 省略可。スクリプトを内部で実行する JavaScript 環境。デフォルトは ISOLATED です。関連項目 隔離された世界で作業する

動的宣言を使用して挿入する

動的コンテンツ スクリプトは、コンテンツ スクリプトの一致パターンが コンテンツ スクリプトを必ずしも既知のホストに挿入してはならないという場合です。

Chrome 96 で導入された動的な宣言は静的 コンテンツ スクリプト オブジェクトが Chrome に登録されます。 メソッドを、chrome.scripting 名前空間manifest.json.Scripting API では、拡張機能のデベロッパーが これを、次のように変更します。

  • コンテンツ スクリプトを登録します。
  • 登録されているコンテンツ スクリプトのリストを取得します。
  • 登録済みのコンテンツ スクリプトのリストを更新します。
  • 登録済みのコンテンツ スクリプトを削除する

静的宣言と同様に、動的宣言には JavaScript ファイル、CSS ファイル、またはその両方を含めることができます。

service-worker.js

chrome.scripting
  .registerContentScripts([{
    id: "session-script",
    js: ["content.js"],
    persistAcrossSessions: false,
    matches: ["*://example.com/*"],
    runAt: "document_start",
  }])
  .then(() => console.log("registration complete"))
  .catch((err) => console.warn("unexpected error", err))

service-worker.js

chrome.scripting
  .updateContentScripts([{
    id: "session-script",
    excludeMatches: ["*://admin.example.com/*"],
  }])
  .then(() => console.log("registration updated"));

service-worker.js

chrome.scripting
  .getRegisteredContentScripts()
  .then(scripts => console.log("registered content scripts", scripts));

service-worker.js

chrome.scripting
  .unregisterContentScripts({ ids: ["session-script"] })
  .then(() => console.log("un-registration complete"));

プログラムによる挿入

イベントまたは特定のイベントに応答して実行する必要があるコンテンツ スクリプトには、プログラマティック インジェクションを使用します。 できます。

コンテンツ スクリプトをプログラムで挿入するには、拡張機能に以下に対するホスト権限が必要です。 挿入しようとしているページに応じて異なります。ホスト権限は、GKE クラスタまたは 拡張機能のマニフェストの一部としてリクエストするか、一時的に "activeTab" を使用してリクエストします。

以下は、activeTab ベースの拡張機能の異なるバージョンです。

manifest.json:

{
  "name": "My extension",
  ...
  "permissions": [
    "activeTab",
    "scripting"
  ],
  "background": {
    "service_worker": "background.js"
  },
  "action": {
    "default_title": "Action Button"
  }
}

コンテンツ スクリプトはファイルとして挿入できます。

content-script.js


document.body.style.backgroundColor = "orange";

service-worker.js:

chrome.action.onClicked.addListener((tab) => {
  chrome.scripting.executeScript({
    target: { tabId: tab.id },
    files: ["content-script.js"]
  });
});

関数本体をコンテンツ スクリプトとして挿入して実行することもできます。

service-worker.js:

function injectedFunction() {
  document.body.style.backgroundColor = "orange";
}

chrome.action.onClicked.addListener((tab) => {
  chrome.scripting.executeScript({
    target : {tabId : tab.id},
    func : injectedFunction,
  });
});

注入される関数は、Terraform で参照されている関数のコピーである (元の関数自体ではなく)chrome.scripting.executeScript() 呼び出し。その結果、関数の 本文は自己完結型でなければなりません。関数外の変数を参照すると、コンテンツの中身が ReferenceError をスローします。

関数として挿入する場合は、関数に引数を渡すこともできます。

service-worker.js

function injectedFunction(color) {
  document.body.style.backgroundColor = color;
}

chrome.action.onClicked.addListener((tab) => {
  chrome.scripting.executeScript({
    target : {tabId : tab.id},
    func : injectedFunction,
    args : [ "orange" ],
  });
});

一致と glob を除外する

指定したページ マッチングをカスタマイズするには、次のフィールドを宣言型に含めます 登録できます。

名前 説明
exclude_matches array of strings 省略可。このコンテンツ スクリプトが挿入されるはずのページが除外されます できます。一致パターンの構文の詳細については、一致パターンをご覧ください。 使用します。
include_globs array of strings 省略可。次を含む URL のみを含めるために、matches の後に適用しました この glob に一致します。これは、@include をエミュレートするためのものです。 Greasemonkey のキーワード。
exclude_globs 文字列の配列 省略可。これに一致する URL を除外するため、matches の後に適用しました glob@exclude をエミュレートすることを目的としています Greasemonkey のキーワード。

次の条件が両方とも満たされている場合、コンテンツ スクリプトはページに挿入されます。

  • その URL は、任意の matches パターンと任意の include_globs パターンに一致します。
  • URL が exclude_matches パターンまたは exclude_globs パターンとも一致しない。 matches プロパティは必須であるため、exclude_matchesinclude_globsexclude_globs は、影響を受けるページを制限する場合にのみ使用できます。

次の拡張機能は、コンテンツ スクリプトを https://www.nytimes.com/health に挿入します。 https://www.nytimes.com/business には含めないでください。

manifest.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.nytimes.com/*"],
      "exclude_matches": ["*://*/*business*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

service-worker.js

chrome.scripting.registerContentScripts([{
  id : "test",
  matches : [ "https://*.nytimes.com/*" ],
  excludeMatches : [ "*://*/*business*" ],
  js : [ "contentScript.js" ],
}]);

glob プロパティは、一致パターンとは異なる、より柔軟な構文に従います。使用できる glob 文字列は、「ワイルドカード」を含む可能性のある URL です。使用しないでください。アスタリスク(*) 空の文字列を含む任意の長さの文字列に一致しますが、疑問符(?)は 使用できます。

たとえば、glob https://???.example.com/foo/\* は、次のいずれかに一致します。

  • https://www.example.com/foo/bar
  • https://the.example.com/foo/

ただし、以下とは一致しません

  • https://my.example.com/foo/bar
  • https://example.com/foo/
  • https://www.example.com/foo

この拡張機能により、コンテンツ スクリプトが https://www.nytimes.com/arts/index.html に挿入され、 https://www.nytimes.com/jobs/index.htm*。ただし、 https://www.nytimes.com/sports/index.html:

manifest.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.nytimes.com/*"],
      "include_globs": ["*nytimes.com/???s/*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

この拡張機能により、コンテンツ スクリプトが https://history.nytimes.com に挿入され、 https://.nytimes.com/history。ただし、https://science.nytimes.com または https://www.nytimes.com/science:

manifest.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.nytimes.com/*"],
      "exclude_globs": ["*science*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

適切なスコープを得るために、これらの 1 つ、すべて、または一部を含めることができます。

manifest.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.nytimes.com/*"],
      "exclude_matches": ["*://*/*business*"],
      "include_globs": ["*nytimes.com/???s/*"],
      "exclude_globs": ["*science*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

実行日時

run_at フィールドは、JavaScript ファイルをウェブページに挿入するタイミングを制御します。推奨される Pod と デフォルト値は "document_idle" です。その他の使用可能なタイプについては、RunAt 型を参照 使用できます。

manifest.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.nytimes.com/*"],
      "run_at": "document_idle",
      "js": ["contentScript.js"]
    }
  ],
  ...
}

service-worker.js

chrome.scripting.registerContentScripts([{
  id : "test",
  matches : [ "https://*.nytimes.com/*" ],
  runAt : "document_idle",
  js : [ "contentScript.js" ],
}]);
名前 説明
document_idle 文字列 推奨。可能な限り "document_idle" を使用してください。

ブラウザ "document_end" とその直後の間にスクリプトを挿入する時間を選択します。 window.onload イベントが発生します。挿入の正確なタイミングは、ドキュメントの複雑さと 読み込みに時間がかかり、ページの読み込み速度を上げるように最適化されています。

コンテンツ スクリプト 動作している "document_idle" は、 window.onload イベントでは、必ず DOM の完了後に実行されます。もし スクリプトを window.onload の後に実行する必要があるとき、拡張機能は onloaddocument.readyState を使用してすでに配信しています プロパティです。
document_start 文字列 スクリプトは css のファイルより後、他の DOM の前に挿入される 他のスクリプトが実行されます。
document_end 文字列 スクリプトは、DOM が完了した後、次のようなサブリソースの前に挿入されます。 画像とフレームが読み込まれました。

フレームを指定する

"all_frames" フィールドを使用すると、JavaScript ファイルと CSS ファイルを使用するかどうかを拡張機能で指定できます。 指定された URL 要件に一致するすべてのフレームに挿入されるか、 タブです。

manifest.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.nytimes.com/*"],
      "all_frames": true,
      "js": ["contentScript.js"]
    }
  ],
  ...
}

service-worker.js

chrome.scripting.registerContentScripts([{
  id: "test",
  matches : [ "https://*.nytimes.com/*" ],
  allFrames : true,
  js : [ "contentScript.js" ],
}]);
名前 説明
all_frames ブール値 省略可。デフォルトは false で、つまり、トップフレームのみが

true を指定すると、すべてのフレームが注入されます。 フレームがタブの一番上のフレームではありません。各フレームは個別に URL と 提供します。URL の要件を満たしていない場合、子フレームには挿入されません。

拡張機能は、一致に関連するフレームでスクリプトを実行する場合があります。 それ自体は一致しません一般的なシナリオは 一致するフレームによって作成された URL を持つが、その URL が スクリプトの指定パターンに一致するかを確認します。

たとえば、拡張機能が、この URL をフレームに挿入し、 about:data:blob:filesystem: のスキームがある。このような場合、 URL はコンテンツ スクリプトのパターンと一致しません(about:data: です。親 URL やオリジンも URL に含めないでください (about:blankdata:text/html,<html>Hello, World!</html> など)。 ただし、これらのフレームは作成中のフレームに関連付けることができます。

これらのフレームに挿入するため、拡張機能は コンテンツ スクリプト仕様の "match_origin_as_fallback" プロパティを 使用します。

manifest.json

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["https://*.google.com/*"],
      "match_origin_as_fallback": true,
      "js": ["contentScript.js"]
    }
  ],
  ...
}

これを指定して true に設定した場合、Chrome は イニシエータが、一致しているかどうかを判定します。 フレーム自体の URL を指定します。また、 ターゲット フレームの origin(例:data: の URL オリジンが null)。

フレームの開始元は、ターゲットを作成または移動したフレーム クリックします。通常は直接的な親またはオープナーですが、そうでない場合もあります( (例: iframe 内の iframe を操作する)

これはイニシエータ フレームの origin を比較するため、イニシエータ フレームは そのオリジンからの任意のパスに限ります。まず、Chrome は "match_origin_as_fallback" で指定されたコンテンツ スクリプトが必要です。 * のパスも指定するには true に設定します。

"match_origin_as_fallback""match_about_blank" の両方を指定すると、 "match_origin_as_fallback" が優先されます。

エンベディング ページとの通信

コンテンツ・スクリプトの実行環境とスクリプトをホストするページは分離されていますが、 ページの DOM へのアクセスを共有します。ページから外部システムへの通信を コンテンツ スクリプト、またはコンテンツ スクリプトによる拡張機能を使用する場合は、共有 DOM を介して実行する必要があります。

たとえば、window.postMessage() を使用して実現できます。

content-script.js

var port = chrome.runtime.connect();

window.addEventListener("message", (event) => {
  // We only accept messages from ourselves
  if (event.source !== window) {
    return;
  }

  if (event.data.type && (event.data.type === "FROM_PAGE")) {
    console.log("Content script received: " + event.data.text);
    port.postMessage(event.data.text);
  }
}, false);

example.js

document.getElementById("theButton").addEventListener("click", () => {
  window.postMessage(
      {type : "FROM_PAGE", text : "Hello from the webpage!"}, "*");
}, false);

拡張機能でないページ example.html は、そのページにメッセージを投稿します。このメッセージは傍受され、 コンテンツ スクリプトによって検査され、拡張機能プロセスに送信されます。このように 拡張機能プロセスへの通信ラインを確立します。その逆も、 同じ意味です

拡張機能ファイルにアクセスする

コンテンツ スクリプトから拡張機能ファイルにアクセスするには、 chrome.runtime.getURL() を使用して、拡張機能アセットの絶対 URL を取得します。次の例(content.js)をご覧ください。

content-script.js

let image = chrome.runtime.getURL("images/my_image.png")

CSS ファイルでフォントや画像を使用するには、@@extension_id を使用して URL を作成します。次の例(content.css)をご覧ください。

content.css

body {
 background-image:url('chrome-extension://__MSG_@@extension_id__/background.png');
}

@font-face {
 font-family: 'Stint Ultra Expanded';
 font-style: normal;
 font-weight: 400;
 src: url('chrome-extension://__MSG_@@extension_id__/fonts/Stint Ultra Expanded.woff') format('woff');
}

すべてのアセットは、manifest.json ファイルでウェブアクセス可能なリソースとして宣言する必要があります。

manifest.json

{
 ...
 "web_accessible_resources": [
   {
     "resources": [ "images/*.png" ],
     "matches": [ "https://example.com/*" ]
   },
   {
     "resources": [ "fonts/*.woff" ],
     "matches": [ "https://example.com/*" ]
   }
 ],
 ...
}

安全の確保

隔離された世界は保護レイヤを提供しますが、コンテンツスクリプトを使用することにより、 ウェブページに存在する脆弱性です。コンテンツ スクリプトが fetch() を呼び出すなどして、コンテンツをフィルタするために クロスサイト スクリプティング攻撃を検出します。以下の目的でのみ、HTTPS 経由で通信します。 &quot;man-in-the-middle&quot;攻撃を回避できます。

悪意のあるウェブページを必ずフィルタしてください。たとえば、次のパターンは危険であり、 Manifest V3 で許可されていない:

すべきでないこと

content-script.js

const data = document.getElementById("json-data");
// WARNING! Might be evaluating an evil script!
const parsed = eval("(" + data + ")");
すべきでないこと

content-script.js

const elmt_id = ...
// WARNING! elmt_id might be '); ... evil script ... //'!
window.setTimeout("animate(" + elmt_id + ")", 200);

代わりに、スクリプトを実行しないより安全な API を使用します。

すべきこと

content-script.js

const data = document.getElementById("json-data")
// JSON.parse does not evaluate the attacker's scripts.
const parsed = JSON.parse(data);
すべきこと

content-script.js

const elmt_id = ...
// The closure form of setTimeout does not evaluate scripts.
window.setTimeout(() => animate(elmt_id), 200);