Inhaltsskripte

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 von Inhaltsscripts

Content-Scripts können über den Austausch von Nachrichten mit der übergeordneten Erweiterung auf Chrome-APIs zugreifen, die von dieser Erweiterung verwendet werden. Sie können auch mit chrome.runtime.getURL() auf die URL der Datei einer Erweiterung zugreifen und das Ergebnis wie bei anderen 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 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 Inhaltsscripts, die Erweiterung und die Webseite nicht auf Variablen oder Funktionen zugreifen, 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 eingefügt 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 der vorübergehende Zugriff auf die Berechtigung tabs gewährt. So kann das Inhaltsskript auf dem aktuell aktiven Tab ausgeführt werden, ohne Berechtigungen für mehrere Herkunftswebsites anzugeben.

{
  "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 Scripts werden im Manifest im Feld "content_scripts" registriert. Sie können JavaScript- oder 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 Inhalts-Script eingefügt werden soll. Weitere Informationen zur Syntax dieser Strings finden Sie unter Übereinstimmungsmuster. Unter Übereinstimmungsmuster und Glob-Strings erfahren Sie, wie Sie URLs ausschließen.
css {: #css } Stringarray 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 erscheinen, bevor ein DOM für die Seite erstellt oder angezeigt wird.
js {: #js } Stringarray Optional. 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 erscheinen.
match_about_blank {: #match_about_blank } boolean Optional. Gibt an, ob das Script in einen about:blank-Frame eingefügt werden soll, dessen übergeordnetes Element oder Öffner-Frame mit einem der in matches angegebenen 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 matches angewendet, um nur URLs einzubeziehen, die auch mit diesem Globus übereinstimmen. Emuliert das Greasemonkey-Keyword @include.
exclude_globs {: #exclude_globs } String-Array Optional. Wird nach matches angewendet, um URLs auszuschließen, die mit diesem Globus übereinstimmen. Emuliert das Greasemonkey-Keyword @exclude.

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 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-Properties folgen einer anderen, flexibleren Syntax als Übereinstimmungsmuster. Zulässige Glob-Strings sind URLs, die Platzhaltersternchen und Fragezeichen enthalten können. Das Sternchen * entspricht einem beliebigen String beliebiger Länge, einschließlich eines leeren Strings. Das Fragezeichen ? stimmt mit einem beliebigen einzelnen Zeichen überein.

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

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

Sie stimmen jedoch nicht mit folgenden Elementen überein:

  • http:// meinewebsite .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 dieser Optionen verwenden, um den gewünschten 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

Wann JavaScript-Dateien in die Webseite eingefügt 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. Verwenden Sie nach Möglichkeit "document_idle".

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

Inhaltsscripts, die bei "document_idle" ausgeführt werden, müssen nicht auf das Ereignis window.onload warten. Sie werden garantiert ausgeführt, nachdem das DOM fertig 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 Scripts werden nach allen Dateien aus css eingefügt, aber bevor ein anderes DOM erstellt oder ein anderes Script 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

Im 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. Standardmäßig ist false festgelegt, d. h., es wird nur der oberste Frame abgeglichen.

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

Kommunikation mit der Seite, auf der die Einbettung erfolgt

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 Inhaltsskript oder über das Inhaltsskript mit der Erweiterung 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 über die Seite eine Kommunikationsverbindung zum Verlängerungsprozess hergestellt. Das Umgekehrte ist auf ähnliche Weise möglich.

Schutzfunktionen

Isolierte Welten bieten zwar einen gewissen Schutz, aber die Verwendung von Inhaltsscripts kann Sicherheitslücken in einer Erweiterung und auf der Webseite verursachen. Wenn das Inhaltsskript Inhalte von einer anderen Website empfängt, z. B. durch ein XMLHttpRequest, sollten Sie Cross-Site-Scripting-Angriffe vor dem Einschleusen filtern. Kommunizieren Sie nur über HTTPS, um "man-in-the-middle" 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);

Verwenden Sie stattdessen sicherere APIs, die keine Scripts 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);