Inhaltsscripts

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

Funktionen des Content-Scripts

Inhaltsskripte können Nachrichten austauschen, um auf Chrome APIs zuzugreifen, die von ihrer übergeordneten Erweiterung verwendet werden durch die Erweiterung. Sie können auch die URL einer Erweiterungsdatei mit chrome.runtime.getURL() und verwenden Sie das Ergebnis wie bei anderen URLs.

// 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 Content-Script direkt auf die folgenden Chrome-APIs zugreifen:

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

In isolierten Welten arbeiten

Content-Scripts sind in einer isolierten Umgebung ausgeführt. So kann ein Content-Script Änderungen an seiner JavaScript-Umgebung vornehmen, ohne dass es zu Konflikten mit der Seite oder zusätzlichen Content-Scripts kommt.

Eine Erweiterung kann auf einer Webseite mit 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);

Wenn die Taste gedrückt wird, werden beide Benachrichtigungen angezeigt.

In isolierten Welten können Inhaltsskripte, die Erweiterung und die Webseite nicht auf beliebige Elemente Variablen oder Funktionen, die von den anderen erstellt wurden. Außerdem können Inhaltsscripts Funktionen aktivieren, die für die Webseite nicht zugänglich sein sollten.

Skripts einschleusen

Content Scripts können programmatisch oder deklarativ eingeschleust werden.

Programmatisch einschleusen

Verwenden Sie die programmatische Insertion für Inhaltsscripts, die bei bestimmten Gelegenheiten ausgeführt werden müssen.

Wenn Sie ein Script für programmatische Inhalte einfügen möchten, geben Sie im Manifest die Berechtigung activeTab an. Dadurch wird der sichere Zugriff auf den Host der aktiven Website und vorübergehender Zugriff auf die Tabs gewährt. Berechtigung, mit der das Inhaltsskript auf dem aktuell aktiven Tab ausgeführt werden kann, ohne ursprungsübergreifenden Berechtigungen.

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

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

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

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

Deklarativ eingefügte Skripts werden im Manifest unter dem 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 } Stringarray Erforderlich. Gibt an, in welche Seiten dieses Inhaltsskript eingeschleust wird. Weitere Informationen zur Syntax dieser Strings finden Sie unter Abgleichsmuster. Informationen zum Ausschließen von URLs finden Sie unter Abgleichsmuster und Globs.
css {: #css } Stringarray Optional. Die Liste der CSS-Dateien, die in übereinstimmende Seiten eingefügt werden sollen. 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 } Stringarray Optional. Die Liste der JavaScript-Dateien, die in übereinstimmende Seiten eingeschleust werden sollen. 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, bei dem der übergeordnete oder Opener-Frame mit einem der in matches deklarierten Muster übereinstimmt. Die Standardeinstellung ist false.

Übereinstimmungen und globs ausschließen

Die angegebene Seitenabgleichsfunktion kann angepasst werden, indem Sie die folgenden Felder in die Manifestregistrierung aufnehmen.

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

Das Inhaltsskript 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 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 würde das Content-Skript in http://www.nytimes.com/ health einschleusen. aber nicht in http://www.nytimes.com/ business .

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

Glob-Eigenschaften folgen einer anderen, flexibleren Syntax als Übereinstimmungsmuster. Zulässige Glob-Strings sind URLs, die Platzhaltersternchen und Fragezeichen enthalten können. Das Sternchen * entspricht beliebigen Strings beliebiger Länge, einschließlich des leeren Strings, während das Fragezeichen ? stimmt überein mit aus einem beliebigen Zeichen.

Beispiel: Der glob http:// ??? .beispiel.de/foo/ * stimmt mit einem der folgenden überein:

  • http:// www .beispiel.de/foo /bar
  • http://beispiel.de/foo/

Folgendes stimmt jedoch nicht überein:

  • http:// mein .beispiel.de/foo/bar
  • http://beispiel.de/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, 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 einschleusen, 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"]
    }
  ],
  ...
}

Sie können eine, alle oder einige davon einschließen, 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"]
    }
  ],
  ...
}

Laufzeit

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

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

Content-Skripts, die unter "document_idle" ausgeführt werden, müssen nicht auf das window.onload-Ereignis warten, sondern werden garantiert ausgeführt, nachdem das DOM abgeschlossen ist. Wenn ein Script unbedingt nach window.onload ausgeführt werden muss, kann die Erweiterung mithilfe der Property document.readyState prüfen, ob onload bereits ausgelöst wurde.
document_start {: #document_start } String Skripts werden nach allen Dateien aus css eingeschleust, aber bevor ein anderes DOM erstellt oder ein anderes Skript ausgeführt wird.
document_end {: #document_end } String Scripts werden unmittelbar nach dem Erstellen des DOMs eingefügt, aber bevor untergeordnete Ressourcen 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 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. Die Standardeinstellung ist false. Das bedeutet, dass nur der oberste Frame abgeglichen wird.

Wenn Sie true angeben, wird der Frame 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. Wenn die URL-Anforderungen nicht erfüllt sind, wird der Frame nicht in untergeordnete Frames eingefügt.

Kommunikation mit der Einbettungsseite

Obwohl die Ausführungsumgebungen von Inhaltsscripts und die Seiten, auf denen sie gehostet werden, voneinander isoliert sind, teilen sie sich den 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 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 abgefangen und vom Content-Skript überprüft und dann an den Erweiterungsprozess gesendet. So wird über die Seite eine Kommunikationsverbindung zum Verlängerungsprozess hergestellt. Umgekehrt ist es möglich, auf ähnliche Weise ausdrücken.

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. mit XMLHttpRequest), achten Sie darauf, Inhalte websiteübergreifend Skriptangriffen vor dem Einschleusen. Kommunizieren Sie nur über HTTPS, um Man-in-the-Middle-Angriffe zu vermeiden.

Filtern Sie auch 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);

Stattdessen sollten Sie sicherere APIs bevorzugen, 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);