Inhaltsscripts

Content-Scripts sind Dateien, die im Kontext von Webseiten ausgeführt werden. Mithilfe des Standard-Document Object Model (DOM) können sie Details der vom Browser besuchten Webseiten lesen, Änderungen daran vornehmen und Informationen an ihre übergeordnete Erweiterung weitergeben.

Funktionen von Content-Scripts

Content-Scripts können auf Chrome-APIs zugreifen, die von ihrer übergeordneten Erweiterung verwendet werden, indem sie Nachrichten mit der Erweiterung austauschen. Sie können auch mit chrome.runtime.getURL() auf die URL einer Erweiterungsdatei zugreifen und das Ergebnis wie andere URLs verwenden.

// Code for displaying EXTENSION_DIR/images/myimage.png:
var imgURL = chrome.runtime.getURL("images/myimage.png");
document.getElementById("someImage").src = imgURL;

Außerdem kann das Content-Script direkt auf die folgenden Chrome-APIs zugreifen:

Content-Scripts können nicht direkt auf andere APIs zugreifen.

In isolierten Umgebungen arbeiten

Content-Skripts werden in einer isolierten Umgebung ausgeführt. So kann ein Content-Skript Änderungen an seiner JavaScript-Umgebung vornehmen, ohne mit der Seite oder zusätzlichen Content-Skripts in Konflikt zu geraten.

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

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

Diese Erweiterung könnte das folgende Inhaltsskript einfügen.

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

Beide Benachrichtigungen werden angezeigt, wenn die Taste gedrückt wird.

In isolierten Welten können Inhaltsskripts, die Erweiterung und die Webseite nicht auf Variablen oder Funktionen zugreifen, die von den anderen erstellt wurden. Dadurch können Content-Scripts auch Funktionen aktivieren, auf die die Webseite nicht zugreifen sollte.

Skripts einschleusen

Content-Scripts können programmatisch oder deklarativ eingefügt werden.

Programmatisch einfügen

Verwenden Sie die programmatische Einfügung für Inhaltsskripts, die zu bestimmten Anlässen ausgeführt werden müssen.

Wenn Sie ein programmatisches Inhaltsscript einschleusen möchten, geben Sie im Manifest die Berechtigung activeTab an. Dadurch wird ein sicherer Zugriff auf den Host der aktiven Website und ein temporärer Zugriff auf die Berechtigung tabs gewährt. So kann das Inhaltsscript auf dem aktuell aktiven Tab ausgeführt werden, ohne dass Berechtigungen für ursprungsübergreifende Anfragen angegeben werden müssen.

{
  "name": "My extension",
  ...
  "permissions": [
    "activeTab"
  ],
  ...
}

Inhaltsskripte können als Code eingefügt werden.

chrome.runtime.onMessage.addListener(
  function(message, callback) {
    if (message == "changeColor"){
      chrome.tabs.executeScript({
        code: 'document.body.style.backgroundColor="orange"'
      });
    }
  });

Oder es kann eine ganze Datei eingefügt werden.

chrome.runtime.onMessage.addListener(
  function(message, callback) {
    if (message == "runContentScript"){
      chrome.tabs.executeScript({
        file: 'contentScript.js'
      });
    }
  });

Deklarativ einschleusen

Verwenden Sie die deklarative Injection für Content-Scripts, die automatisch auf bestimmten Seiten ausgeführt werden sollen.

Deklarativ eingefügte Skripts werden im Manifest im Feld "content_scripts" registriert. Sie können JavaScript-Dateien, CSS-Dateien oder beides enthalten. Für alle automatisch ausgeführten Inhaltsscripts müssen Übereinstimmungsmuster angegeben werden.

{
 "name": "My extension",
 ...
 "content_scripts": [
   {
     "matches": ["http://*.nytimes.com/*"],
     "css": ["myStyles.css"],
     "js": ["contentScript.js"]
   }
 ],
 ...
}
Name Typ Beschreibung
matches {: #matches } String-Array Erforderlich. Gibt an, auf welchen Seiten dieses Inhaltsscript eingefügt wird. Weitere Informationen zur Syntax dieser Strings finden Sie unter Übereinstimmungsmuster. Informationen zum Ausschließen von URLs finden Sie unter Übereinstimmungsmuster und Globs.
css {: #css } String-Array Optional. Die Liste der CSS-Dateien, die in übereinstimmende Seiten eingefügt werden sollen. Sie werden in der Reihenfolge eingefügt, in der sie in diesem Array aufgeführt sind, bevor ein DOM für die Seite erstellt oder angezeigt wird.
js {: #js } String-Array Optional. Die Liste der JavaScript-Dateien, die in übereinstimmende Seiten eingefügt werden sollen. Sie werden in der Reihenfolge eingefügt, in der sie in diesem Array aufgeführt sind.
match_about_blank {: #match_about_blank } boolean Optional. Gibt an, ob das Script in einen about:blank-Frame eingefügt werden soll, in dem der übergeordnete Frame oder der Frame, der das Fenster geöffnet hat, mit einem der in matches deklarierten Muster übereinstimmt. Die Standardeinstellung ist false.

Übereinstimmungen und Globs ausschließen

Die angegebene Seitenübereinstimmung kann angepasst werden, indem die folgenden Felder in die Manifestregistrierung aufgenommen werden.

Name Typ Beschreibung
exclude_matches {: #exclude_matches } String-Array Optional. Schließt Seiten aus, in die dieses Inhaltsscript ansonsten eingefügt würde. Weitere Informationen zur Syntax dieser Strings finden Sie unter Übereinstimmungsmuster.
include_globs {: #include_globs } String-Array Optional. Wird nach matches angewendet, um nur URLs einzuschließen, die auch mit diesem Glob übereinstimmen. Soll das Greasemonkey-Keyword @include emulieren.
exclude_globs {: #exclude_globs } String-Array Optional. Wird nach matches angewendet, um URLs auszuschließen, die mit diesem Glob übereinstimmen. Soll das @excludeGreasemonkey-Keyword emulieren.

Das Content-Script wird in eine Seite eingefügt, wenn ihre URL mit einem matches-Muster und einem include_globs-Muster übereinstimmt, sofern die URL nicht auch mit einem exclude_matches- oder exclude_globs-Muster übereinstimmt.

Da die Property matches erforderlich ist, können exclude_matches, include_globs und exclude_globs nur verwendet werden, um die betroffenen Seiten einzuschränken.

Die folgende Erweiterung würde das Inhaltsskript in http://www.nytimes.com/ health, aber nicht in http://www.nytimes.com/ business einfügen .

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

Für Glob-Properties gilt eine andere, flexiblere Syntax als für Abgleichsmuster. Zulässige Glob-Strings sind URLs, die Platzhalter-Sternchen und Fragezeichen enthalten können. Das Sternchen * entspricht einem beliebigen String beliebiger Länge, einschließlich des leeren Strings, während das Fragezeichen ? entspricht einem beliebigen einzelnen Zeichen.

Das Glob-Muster http:// ??? .beispiel.de/foo/ * stimmt beispielsweise mit den folgenden URLs überein:

  • http:// www .beispiel.de/foo /bar
  • http:// the .example.com/foo /

Sie stimmt jedoch nicht mit Folgendem überein:

  • http:// my .example.com/foo/bar
  • http:// beispiel .de/foo/
  • http://www.example.com/foo

Diese Erweiterung würde das Content-Script in http:/www.nytimes.com/ arts /index.html und http://www.nytimes.com/ jobs /index.html einfügen, aber nicht in http://www.nytimes.com/ sports /index.html.

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

Diese Erweiterung würde das Inhaltsskript in http:// history .nytimes.com und http://.nytimes.com/ history einfügen, aber nicht in http:// science .nytimes.com oder http://www.nytimes.com/ science .

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

Je nach gewünschtem Umfang können Sie einen, alle oder einige dieser Parameter einbeziehen.

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

Laufzeit

Mit dem Feld run_at wird gesteuert, wann JavaScript-Dateien in die Webseite eingefügt werden. Das bevorzugte und standardmäßige Feld ist "document_idle". Es kann bei Bedarf aber auch als "document_start" oder "document_end" angegeben werden.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "run_at": "document_idle",
      "js": ["contentScript.js"]
    }
  ],
  ...
}
Name Typ Beschreibung
document_idle {: #document_idle } String Bevorzugt. Verwenden Sie nach Möglichkeit "document_idle".

Der Browser wählt einen Zeitpunkt für das Einschleusen von Scripts zwischen "document_end" und unmittelbar nach dem Auslösen des windowonload-Ereignisses aus. Der genaue Zeitpunkt der Einfügung hängt davon ab, wie komplex das Dokument ist und wie lange es dauert, bis es geladen wird. Er wird für den Seitenaufbau optimiert.

Inhalts-Scripts, die unter "document_idle" ausgeführt werden, müssen nicht auf das window.onload-Ereignis warten. Sie werden garantiert nach Abschluss des DOM ausgeführt. Wenn ein Skript unbedingt nach window.onload ausgeführt werden muss, kann die Erweiterung mit der Property document.readyState prüfen, ob onload bereits ausgelöst wurde.
document_start {: #document_start } String Scripts werden nach allen Dateien aus css, aber vor der Erstellung von anderem DOM oder der Ausführung anderer Scripts eingefügt.
document_end {: #document_end } String Scripts werden unmittelbar nach dem DOM eingefügt, aber bevor Subressourcen wie Bilder und Frames geladen wurden.

Frames angeben

Mit dem Feld "all_frames" kann die Erweiterung angeben, ob JavaScript- und CSS-Dateien in alle Frames eingefügt werden sollen, die den angegebenen Anforderungen an URLs entsprechen, oder nur in den obersten Frame auf einem Tab.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "all_frames": true,
      "js": ["contentScript.js"]
    }
  ],
  ...
}
Name Typ Beschreibung
all_frames {: #all_frames } boolean Optional. Der Standardwert ist false. Das bedeutet, dass nur der oberste Frame abgeglichen wird.

Wenn true angegeben ist, wird der Code in alle Frames eingefügt, auch wenn der Frame nicht der oberste Frame auf dem Tab ist. Jeder Frame wird unabhängig auf Anforderungen an URLs geprüft. Wenn die Anforderungen an URLs nicht erfüllt sind, wird der Code nicht in untergeordnete Frames eingefügt.

Kommunikation mit der Einbettungsseite

Obwohl die Ausführungsumgebungen von Inhaltsskripts und den Seiten, auf denen sie gehostet werden, voneinander isoliert sind, haben sie Zugriff auf das DOM der Seite. Wenn die Seite mit dem Content-Script oder mit der Erweiterung über das Content-Script kommunizieren möchte, muss dies über das gemeinsame DOM erfolgen.

Ein Beispiel mit window.postMessage:

var port = chrome.runtime.connect();

window.addEventListener("message", function(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);
document.getElementById("theButton").addEventListener("click",
    function() {
  window.postMessage({ type: "FROM_PAGE", text: "Hello from the webpage!" }, "*");
}, false);

Die Seite ohne Erweiterung, example.html, sendet Nachrichten an sich selbst. Diese Nachricht wird vom Inhaltsskript abgefangen und geprüft und dann an den Erweiterungsprozess gesendet. So wird eine Kommunikationslinie zum Erweiterungsprozess eingerichtet. Das Gegenteil ist auf ähnliche Weise möglich.

Schutzfunktionen

Isolierte Welten bieten zwar eine Schutzebene, die Verwendung von Inhaltskripten kann jedoch zu Sicherheitslücken in einer Erweiterung und auf der Webseite führen. Wenn das Content-Script Inhalte von einer separaten Website empfängt, z. B. durch einen XMLHttpRequest, sollten Sie die Inhalte sorgfältig filtern, um websiteübergreifende Scripting-Angriffe zu vermeiden, bevor Sie sie einfügen. Kommunizieren Sie nur über HTTPS, um "man-in-the-middle" zu vermeiden.

Filtern Sie unbedingt nach schädlichen Webseiten. Die folgenden Muster sind beispielsweise gefährlich:

var data = document.getElementById("json-data")
// WARNING! Might be evaluating an evil script!
var parsed = eval("(" + data + ")")
var elmt_id = ...
// WARNING! elmt_id might be "); ... evil script ... //"!
window.setTimeout("animate(" + elmt_id + ")", 200);

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

var data = document.getElementById("json-data")
// JSON.parse does not evaluate the attacker's scripts.
var parsed = JSON.parse(data);
var elmt_id = ...
// The closure form of setTimeout does not evaluate scripts.
window.setTimeout(function() {
  animate(elmt_id);
}, 200);