Inhaltsskripte

Inhaltsskripte sind Dateien, die im Kontext von Webseiten ausgeführt werden. Das standardmäßige Document Objektmodell (DOM) können sie Details zu den vom Browser besuchten Webseiten lesen, und Informationen an die übergeordnete Erweiterung übergeben.

Funktionen des Content-Scripts

Inhaltsskripte können direkt auf die folgenden Erweiterungs-APIs zugreifen:

Inhaltsskripte können nicht direkt auf andere APIs zugreifen. Nutzer können aber indirekt darauf zugreifen, indem sie Nachrichten mit anderen Teilen der Erweiterung austauschen.

Sie können auch über ein Content-Skript auf andere Dateien in Ihrer Erweiterung zugreifen, indem Sie APIs wie fetch() Dazu müssen Sie sie als über das Web zugängliche Ressourcen. Beachten Sie, dass die Ressourcen dadurch auch für alle eigene oder Drittanbieter-Skripts, die auf derselben Website ausgeführt werden.

In isolierten Welten arbeiten

Inhaltsskripte befinden sich in einer isolierten Welt, sodass ein Inhaltsskript Änderungen an seinem JavaScript-Umgebung ohne Konflikte mit der Seite oder anderen Erweiterungen Inhaltsskripte.

Eine Erweiterung kann auf einer Webseite mit Code ausgeführt werden, der dem folgenden Beispiel ähnelt.

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>

Diese Erweiterung könnte das folgende Inhaltsskript mithilfe einer der in den Abschnitt Scripts einfügen.

content-script.js

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

Durch diese Änderung werden beide Benachrichtigungen nacheinander angezeigt, wenn auf die Schaltfläche geklickt wird.

Skripts einfügen

Content-Skripts können statisch, deklariert dynamisch oder programmatisch eingeschleust werden.

Mit statischen Deklarationen einfügen

Verwenden Sie Deklarationen von statischen Inhalten in der Datei „manifest.json“ für Skripts, die automatisch auf einer bekannten Gruppe von Seiten ausgeführt werden.

Statisch deklarierte Skripts werden im Manifest unter dem Schlüssel "content_scripts" registriert. Sie können JavaScript-Dateien, CSS-Dateien oder beides enthalten. In allen automatisch ausgeführten Content-Skripts muss angegeben werden, Übereinstimmungsmuster.

manifest.json

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

Name Typ Beschreibung
matches String-Array Erforderlich. Gibt an, in welche Seiten dieses Inhaltsskript eingeschleust wird. Weitere Informationen zur Syntax dieser Strings finden Sie unter Übereinstimmungsmuster. und unter Übereinstimmungsmuster und Globs finden Sie Informationen dazu, wie Sie URLs.
css String-Array Optional. Die Liste der CSS-Dateien, die in übereinstimmende Seiten eingeschleust werden sollen. Dies sind in der Reihenfolge injiziert, in der sie in diesem Array erscheinen, bevor ein DOM erstellt oder angezeigt wird für die Seite.
js Stringarray Optional. Die Liste der JavaScript-Dateien, die in übereinstimmende Seiten eingeschleust werden sollen. Dateien in der Reihenfolge eingeschleust, in der sie in diesem Array erscheinen. Jeder String in dieser Liste muss relativen Pfad zu einer Ressource im Stammverzeichnis der Erweiterung. Führende Schrägstriche (/) sind automatisch zugeschnitten.
run_at RunAt Optional. Gibt an, wann das Skript in die Seite eingeschleust werden soll. Standardeinstellung: document_idle
match_about_blank boolean Optional. Legt fest, ob das Skript in einen about:blank-Frame eingefügt werden soll wobei der übergeordnete oder Opener-Frame mit einem der in matches. Die Standardeinstellung ist "false".
match_origin_as_fallback boolean Optional. Ob das Skript Frames einschleusen soll, die die von einem übereinstimmenden Ursprung erstellt wurden, deren URL oder Ursprung aber nicht direkt mit dem Muster übereinstimmen. Dazu gehören auch Frames mit unterschiedlichen Schemas, z. B. about:, data:, blob: und filesystem:. Siehe auch Injection in verwandten Frames
world ExecutionWorld Optional. Die JavaScript-Welt, in der ein Script ausgeführt werden soll. Die Standardeinstellung ist ISOLATED. Siehe auch Arbeiten Sie in isolierten Welten.

Mit dynamischen Deklarationen einfügen

Skripts für dynamische Inhalte sind nützlich, wenn die Abgleichsmuster für Inhaltsskripte nicht bekannt sind oder wenn Inhaltsskripte nicht immer auf bekannten Hosts eingeschleust werden sollten.

Seit der Einführung von Chrome 96 ähneln dynamische Deklarationen statischen Deklarationen. Das Content-Script-Objekt ist jedoch mithilfe von im chrome.scripting-Namespace statt in manifest.json. Mit der Scripting API können auch Entwickler von Erweiterungen in:

Wie statische Deklarationen können auch dynamische Deklarationen JavaScript-Dateien, CSS-Dateien oder beides enthalten.

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"));

Programmatisch einfügen

Verwenden Sie die programmatische Injektion für Content-Skripts, die als Reaktion auf Ereignisse oder bei bestimmten für verschiedene Anlässe.

Um ein Inhaltsskript programmatisch einzufügen, benötigt Ihre Erweiterung Hostberechtigungen für der Seite, auf der Skripte eingeschleust werden sollen. Hostberechtigungen können entweder über das Manifest Ihrer Erweiterung oder vorübergehend über "activeTab" anfordern.

Im Folgenden finden Sie verschiedene Versionen einer aktiven tab-basierten Erweiterung.

manifest.json:

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

Inhaltsskripte können als Dateien eingeschleust werden.

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"]
  });
});

Oder ein Funktionstext kann eingeschleust und als Inhaltsskript ausgeführt werden.

service-worker.js:

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

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

Beachten Sie, dass die injizierte Funktion eine Kopie der Funktion ist, auf die im chrome.scripting.executeScript()-Aufruf, nicht die ursprüngliche Funktion selbst. Daher ist der Wert der Funktion Körper muss in sich geschlossen sein; führen Verweise auf Variablen außerhalb der Funktion dazu, dass der Inhalt zum Auslösen einer ReferenceError.

Beim Einschleusen als Funktion können Sie auch Argumente an die Funktion übergeben.

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" ],
  });
});

Übereinstimmungen und globs ausschließen

Nehmen Sie die folgenden Felder in ein deklaratives Feld auf, um den Seitenabgleich anzupassen: Registrierung.

Name Typ Beschreibung
exclude_matches String-Array Optional. Schließt Seiten aus, auf die dieses Inhaltsskript andernfalls eingeschleust würde in die Sie hineinversetzen können. Weitere Informationen zur Syntax von für diese Zeichenfolgen.
include_globs String-Array Optional. Wird nach dem matches angewendet, um nur die URLs einzuschließen, die auch mit diesem Glob übereinstimmen. Damit soll @include emuliert werden. Greasemonkey-Keyword.
exclude_globs Array von String Optional. Wird nach dem matches angewendet, um entsprechende URLs auszuschließen glob. Soll die @exclude emulieren Greasemonkey-Keyword.

Das Content-Skript wird in eine Seite eingefügt, wenn die beiden folgenden Bedingungen zutreffen:

  • Seine URL stimmt mit jedem matches-Muster und jedem include_globs-Muster überein.
  • Die URL stimmt auch nicht mit dem Muster exclude_matches oder exclude_globs überein. Da das Attribut matches erforderlich ist, exclude_matches, include_globs und exclude_globs lässt sich lediglich einschränken, welche Seiten betroffen sind.

Die folgende Erweiterung fügt das Inhaltsskript in https://www.nytimes.com/health ein aber nicht in 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-Eigenschaften folgen einer anderen, flexibleren Syntax als Übereinstimmungsmuster. Akzeptabler Glob Strings sind URLs, die „Platzhalter“ enthalten können Sternchen und Fragezeichen. Das Sternchen (*) entspricht einem beliebigen String beliebiger Länge, einschließlich des leeren Strings, während das Fragezeichen (?) mit dem aus einem beliebigen Zeichen.

Der glob https://???.example.com/foo/\* stimmt beispielsweise mit einem der folgenden Elemente überein:

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

Folgendes stimmt jedoch nicht überein:

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

Diese Erweiterung fügt das Inhaltsskript in https://www.nytimes.com/arts/index.html und https://www.nytimes.com/jobs/index.htm*, aber nicht in 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"]
    }
  ],
  ...
}

Diese Erweiterung fügt das Inhaltsskript in https://history.nytimes.com und https://.nytimes.com/history, aber nicht in https://science.nytimes.com oder https://www.nytimes.com/science:

manifest.json

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

Sie können eine, alle oder einige davon einschließen, um den richtigen Umfang zu erreichen.

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"]
    }
  ],
  ...
}

Laufzeit

Das Feld run_at steuert, wann JavaScript-Dateien in die Webseite eingeschleust werden. Die bevorzugten und Der Standardwert ist "document_idle". Unter dem RunAt-Typ finden Sie Werte.

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" ],
}]);
Name Typ Beschreibung
document_idle String Bevorzugt. Verwenden Sie nach Möglichkeit "document_idle".

Den Browser wählt einen Zeitpunkt für das Einfügen von Skripts zwischen "document_end" und sofort nach window.onload ausgelöst wird. Der genaue Zeitpunkt der Einschleusung hängt davon ab, wie komplex das Dokument ist wie lange es dauert, bis sie geladen ist, und ist für die Seitenladegeschwindigkeit optimiert.

Content-Scripts die um "document_idle" laufen, müssen nicht window.onload ausführen, werden sie garantiert nach Abschluss des DOMs ausgeführt. Wenn ein Das Skript muss unbedingt nach window.onload ausgeführt werden. Die Erweiterung kann prüfen, onload wurde bereits mithilfe von document.readyState ausgelöst Property.
document_start String Skripts werden nach allen Dateien aus css eingeschleust, aber vor jedem anderen DOM oder ein anderes Skript ausgeführt wird.
document_end String Skripts werden unmittelbar nach Abschluss des DOMs eingeschleust, aber vor Unterressourcen wie Bilder und Frames geladen wurden.

Frames angeben

Im Feld "all_frames" kann die Erweiterung angeben, ob JavaScript- und CSS-Dateien in alle Frames, die den angegebenen URL-Anforderungen entsprechen, oder nur in den obersten Frame einer .

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" ],
}]);
Name Typ Beschreibung
all_frames boolean Optional. Die Standardeinstellung ist false. Das bedeutet, dass nur der oberste Frame stimmt überein.

Wenn true angegeben ist, werden alle Frames eingefügt, auch wenn der ist nicht der oberste Frame in der Registerkarte. Jeder Frame wird separat auf URL geprüft. Anforderungen. Es wird nicht in untergeordnete Frames eingeschleust, wenn die URL-Anforderungen nicht erfüllt sind.

Erweiterungen können Skripts in Frames ausführen, die mit einer übereinstimmenden Frame, aber sie stimmen nicht überein. Ein gängiges Szenario, in dem dies für Frames mit URLs, die von einem übereinstimmenden Frame erstellt wurden, deren URLs jedoch nicht mit den im Skript angegebenen Mustern übereinstimmen.

Dies ist der Fall, wenn eine Erweiterung Frames mit URLs einfügen möchte, haben die Schemas about:, data:, blob: und filesystem:. In diesen Fällen Die URL stimmt nicht mit dem Muster des Content-Skripts überein (und im Fall von about: und data:, fügen Sie nicht einmal die übergeordnete URL oder den Ursprung in die URL ein. überhaupt, wie in about:blank oder data:text/html,<html>Hello, World!</html>). Diese Frames können jedoch immer noch mit dem erstellenden Frame verknüpft werden.

Um in diese Frames einzuschleusen, können Erweiterungen den Parameter "match_origin_as_fallback" in einer Content Script-Spezifikation im Manifests.

manifest.json

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

Wenn dieses Flag angegeben und auf true gesetzt ist, prüft Chrome den Ursprung des Initiator des Frames, um zu bestimmen, ob der Frame übereinstimmt, und nicht die URL des Frames selbst. Beachten Sie, dass sich dieser Wert auch vom Ursprung des Ziel-Frames (z.B. data: URLs haben keinen Ursprung.

Der Initiator des Frames ist der Frame, der das Ziel erstellt oder darauf navigiert hat. Frame. Normalerweise ist dies der direkte übergeordnete Punkt oder die Einleitung, aber nicht unbedingt (wie bei wenn ein Frame in einem iFrame innerhalb eines iFrames navigiert.

Da dabei der origin-Wert des Initiator-Frames verglichen wird, von diesem Ursprung aus auf jedem Pfad möglich sein. Um dies zu verdeutlichen, erfordert alle mit "match_origin_as_fallback" angegebenen Inhaltsskripte auf true gesetzt, um auch den Pfad * anzugeben.

Wenn sowohl "match_origin_as_fallback" als auch "match_about_blank" angegeben sind, "match_origin_as_fallback" hat Priorität.

Kommunikation mit der Einbettungsseite

Obwohl die Ausführungsumgebungen von Inhaltsskripten und die Seiten, auf denen sie gehostet werden, isoliert sind teilen sie Zugriff auf das DOM der Seite. Wenn die Seite mit dem Content-Skript oder mit der Erweiterung über das Content-Skript erstellt werden, muss es dies über das freigegebene DOM tun.

Ein Beispiel hierfür ist mit 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);

Auf der Seite ohne Erweiterung (beispiel.html) werden Nachrichten an sich selbst gesendet. Diese Nachricht wird abgefangen und vom Content-Skript überprüft und dann an den Erweiterungsprozess gesendet. So kann die Seite baut eine Kommunikationsverbindung mit dem Erweiterungsprozess auf. Umgekehrt ist es möglich, auf ähnliche Weise ausdrücken.

Auf Erweiterungsdateien zugreifen

Um aus einem Content-Skript auf eine Erweiterungsdatei zuzugreifen, können Sie Folgendes aufrufen: chrome.runtime.getURL(), um die absolute URL des Erweiterungs-Assets zu erhalten, wie im folgenden Beispiel (content.js) gezeigt:

content-script.js

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

Wenn Sie Schriftarten oder Bilder in einer CSS-Datei verwenden möchten, können Sie mit @@extension_id eine URL erstellen, wie im folgenden Beispiel (content.css) gezeigt:

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');
}

Alle Assets müssen in der Datei manifest.json als über das Internet zugängliche Ressourcen deklariert werden:

manifest.json

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

Schutzfunktionen

Isolierte Welten bieten zwar eine Schutzebene, aber durch die Verwendung von Content-Skripts Sicherheitslücken in einer Erweiterung und auf der Webseite. Wenn das Content-Skript Content von einem separater Website zu erstellen, z. B. durch Aufrufen von fetch(), achten Sie darauf, Cross-Site-Scripting-Angriffe, bevor sie eingeschleust werden. Kommunizieren Sie nur über HTTPS, um &quot;man-in-the-middle&quot; zu vermeiden.

Filtern Sie auch nach schädlichen Webseiten. Zum Beispiel sind die folgenden Muster gefährlich und in Manifest V3 nicht zulässig:

Don'ts

content-script.js

const data = document.getElementById("json-data");
// WARNING! Might be evaluating an evil script!
const parsed = eval("(" + data + ")");
Don'ts

content-script.js

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

Bevorzugen Sie stattdessen sicherere APIs, die keine Skripts ausführen:

Do

content-script.js

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

content-script.js

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