Inhaltsskripte

Content-Skripts sind Dateien, die im Kontext von Webseiten ausgeführt werden. Mithilfe des standardmäßigen Document Object Model (DOM) können sie Details zu den Webseiten lesen, die der Browser besucht, Änderungen daran vornehmen und Informationen an die übergeordnete Erweiterung übergeben.

Content-Script-Funktionen

Inhaltsskripte können auf Chrome APIs zugreifen, die von ihrer übergeordneten Erweiterung verwendet werden, indem Nachrichten mit der Erweiterung ausgetauscht werden. Außerdem kann er mit chrome.runtime.getURL() auf die URL der Datei einer Erweiterung zugreifen und das Ergebnis genauso 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;

Darüber hinaus kann das Inhaltsskript direkt auf die folgenden Chrome-APIs zugreifen:

Inhaltsskripte können nicht direkt auf andere APIs zugreifen.

In isolierten Welten arbeiten

Inhaltsskripte befinden sich in einer isolierten Welt. Dadurch kann ein Inhaltsskript Änderungen an seiner JavaScript-Umgebung vornehmen, ohne dass es zu Konflikten mit der Seite oder zusätzlichen Inhaltsskripten kommt.

Eine Erweiterung kann auf einer Webseite mit einem ähnlichen Code wie im folgenden Beispiel ausgeführt werden.

<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 einschleusen.

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

Beim Drücken der Schaltfläche werden beide Benachrichtigungen angezeigt.

Isolierte Welten lassen es nicht zu, dass Inhaltsskripte, die Erweiterung und die Webseite auf die von den anderen erstellten Variablen oder Funktionen zugreifen. So können Inhaltsskripte auch Funktionen aktivieren, die für die Webseite nicht zugänglich sein sollten.

Skripts einfügen

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

Programmatisch einfügen

Verwenden Sie die programmatische Injektion für Inhaltsskripte, die zu bestimmten Anlässen ausgeführt werden müssen.

Wenn Sie ein Script für programmatischen Content einfügen möchten, geben Sie im Manifest die Berechtigung activeTab an. Dies gewährt sicheren Zugriff auf den Host der aktiven Website und vorübergehenden Zugriff auf die Berechtigung Tabs. Das Inhaltsskript kann dann auf dem aktuellen aktiven Tab ausgeführt werden, ohne ursprungsübergreifende Berechtigungen anzugeben.

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

Inhaltsskripte können als Code eingeschleust werden.

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

Es kann auch eine ganze Datei eingeschleust werden.

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

Deklarativ einfügen

Deklaratives Einschleusen von Inhaltsskripts, die auf bestimmten Seiten automatisch ausgeführt werden sollen

Deklarativ eingefügte Skripts werden im Manifest unter dem Feld "content_scripts" registriert. Sie können JavaScript- und CSS-Dateien oder beides enthalten. Für alle automatisch ausgeführten Inhaltsskripts müssen Abgleichsmuster 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 welche Seiten dieses Inhaltsskript eingeschleust 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 eingeschleust werden. Diese werden in der Reihenfolge eingeschleust, in der sie in diesem Array erscheinen, 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 eingeschleust werden. Diese werden in der Reihenfolge eingeschleust, in der sie in diesem Array vorkommen.
match_about_blank {: #match_about_blank } boolean Optional. Gibt an, ob das Skript in einen about:blank-Frame eingeschleust werden soll, wenn der übergeordnete oder öffnende Frame einem der in matches deklarierten Muster entspricht. Die Standardeinstellung ist false.

Übereinstimmungen und Globs ausschließen

Der angegebene Seitenabgleich 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 Inhaltsskript normalerweise eingeschleust werden 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 die URLs einzuschließen, die auch diesem Glob entsprechen. Dient zur Emulation des Greasemonkey-Keywords @include.
exclude_globs {: #exclusion_globs } Array eines Strings Optional. Wird nach matches angewendet, um URLs auszuschließen, die diesem Glob entsprechen. Dient zur Emulation des Keywords @excludeGreasemonkey.

Das Inhaltsskript wird in eine Seite eingeschleust, wenn ihre URL mit einem matches-Muster und einem beliebigen include_globs-Muster übereinstimmt, sofern die URL nicht auch einem exclude_matches- oder exclude_globs-Muster entspricht.

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

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

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

Glob-Attribute folgen einer anderen, flexibleren Syntax als Übereinstimmungsmuster. Zulässige Glob-Strings sind URLs, die Platzhaltersternchen und Fragezeichen enthalten können. Das Sternchen * entspricht jedem String beliebiger Länge, einschließlich des leeren Strings, während das Fragezeichen ? jedem einzelnen Zeichen entspricht.

Beispielsweise stimmt die glob-Datei http:// ??? .example.com/foo/ * mit einem der folgenden Beispiele überein:

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

Sie entspricht jedoch nicht den folgenden Werten:

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

Diese Erweiterung würde das Inhaltsskript in http:/www.nytimes.com/ Arts /index.html und http://www.nytimes.com/ jobs /index.html einschleusen, jedoch 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, jedoch 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"]
    }
  ],
  ...
}

Eine, alle oder einige davon können einbezogen werden, um den richtigen Umfang zu erreichen.

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

Ausführungszeit

Wenn JavaScript-Dateien in die Webseite eingeschleust werden, wird über das Feld run_at gesteuert. Das bevorzugte und Standardfeld ist "document_idle", kann aber bei Bedarf 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 Verwende nach Möglichkeit "document_idle".

Der Browser wählt einen Zeitpunkt für das Einfügen von Skripts zwischen dem "document_end" und direkt nach dem Auslösen des windowonload-Ereignisses aus. Der genaue Zeitpunkt der Injektion hängt davon ab, wie komplex das Dokument ist und wie lange es dauert, bis das Dokument geladen wird. Das Dokument ist im Hinblick auf die Seitenladegeschwindigkeit optimiert.

Content-Skripts, die unter "document_idle" ausgeführt werden, müssen nicht auf das window.onload-Ereignis warten. Sie werden garantiert ausgeführt, nachdem das DOM abgeschlossen ist. Wenn ein Script definitiv nach window.onload ausgeführt werden muss, kann die Erweiterung mithilfe der document.readyState-Property prüfen, ob onload bereits ausgelöst wurde.
document_start {: #document_start } String Skripts werden nach allen Dateien von css eingeschleust, aber bevor ein anderes DOM erstellt oder ein anderes Skript ausgeführt wird.
document_end {: #document_end } String Skripts werden unmittelbar nach Abschluss des DOMs eingefügt, aber bevor Unterressourcen 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 URL-Anforderungen entsprechen, oder nur im obersten Frame eines Tabs.

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

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

Kommunikation mit der Einbettungsseite

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

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

Auf der Seite ohne Erweiterung, beispiel.html, werden Nachrichten an sich selbst gepostet. Diese Nachricht wird vom Inhaltsskript abgefangen und geprüft und dann an die Erweiterung gesendet. Auf diese Weise stellt die Seite eine Verbindung zum Erweiterungsprozess her. Umgekehrt ist auch auf ähnliche Weise möglich.

Schutzfunktionen

Während isolierte Welten eine Sicherheitsebene bieten, kann die Verwendung von Inhaltsskripten zu Sicherheitslücken in einer Erweiterung und auf der Webseite führen. Wenn das Inhaltsskript Inhalte von einer separaten Website empfängt, z. B. durch eine XMLHttpRequest, achten Sie darauf, Inhalte vor der Einschleusung mit Cross-Site-Scripting-Angriffen zu filtern. Kommunizieren Sie ausschließlich über HTTPS, um "man-in-the-middle"-Angriffe zu vermeiden.

Achten Sie darauf, nach schädlichen Webseiten zu filtern. 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);

Stattdessen sollten Sie sicherere APIs bevorzugen, bei denen keine Skripts ausgeführt werden:

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