Skrypty treści

Skrypty treści to pliki uruchamiane w kontekście stron internetowych. Przy użyciu standardowego Dokumentu modelu obiektowego (DOM), mogą odczytywać szczegóły stron internetowych odwiedzanych przez przeglądarkę, i przekazują informacje do rozszerzenia nadrzędnego.

Omówienie możliwości skryptów treści

Skrypty treści mają bezpośredni dostęp do tych interfejsów API rozszerzeń:

Skrypty treści nie mają bezpośredniego dostępu do innych interfejsów API. Mogą jednak uzyskiwać do nich dostęp pośredni, wymieniając wiadomości z innymi częściami rozszerzenia.

Dostęp do innych plików w rozszerzeniu możesz też uzyskać za pomocą skryptu treści, używając Interfejsy API takie jak fetch(). Aby to zrobić, musisz zadeklarować je jako zasobów dostępnych przez internet. Pamiętaj, że to naraża zasoby również skrypty własne i innych firm działające w tej samej witrynie.

Praca w odizolowanych światach

Skrypty treści funkcjonują w osobnym świecie, dzięki czemu mogą wprowadzać zmiany w środowisku JavaScript, w którym nie występuje konflikt ze stroną lub innymi rozszerzeniami. skrypty treści.

Rozszerzenie może działać na stronie internetowej z kodem podobnym do tego przykładu.

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>

To rozszerzenie może wstrzykiwać następujący skrypt za pomocą jednej z technik opisanych w Wstaw skrypty.

content-script.js

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

Dzięki tej zmianie oba alerty pojawiają się po kliknięciu.

Wstrzykiwanie skryptów

Skrypty treści mogą być statycznie deklarowane, deklarowane dynamicznie lub wstrzykiwana automatycznie.

Wstrzykiwanie z deklaracjami statycznymi

Użyj deklaracji skryptu treści statycznej w pliku manifest.json w przypadku skryptów, które powinny być wykonywane automatycznie na dobrze znanym zestawie stron.

Statycznie zadeklarowane skrypty są zarejestrowane w pliku manifestu w kluczu "content_scripts". Mogą obejmować pliki JavaScript, pliki CSS lub oba te elementy. Wszystkie automatycznie uruchamiane skrypty treści muszą zawierać parametr wzorców dopasowania.

manifest.json

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

Nazwa Typ Opis
matches tablica ciągów Wymagane. Określa strony, na których ten skrypt treści będzie wstrzykiwany. Szczegółowe informacje o składni tych ciągów znajdziesz w sekcji Wzorce dopasowania. oraz wzorce i globy dopasowania, aby dowiedzieć się, jak wykluczać Adresy URL.
css tablica ciągów Opcjonalne. Lista plików CSS do wstrzykiwania do pasujących stron. Są to wstrzykiwane w kolejności, w jakiej występują w tej tablicy, przed utworzeniem lub wyświetleniem DOM dla strony.
js tablica ciągów Opcjonalne. Lista plików JavaScript do wstrzykiwania na pasujących stronach. Pliki są wstrzykiwane w kolejności, w jakiej występują w tej tablicy. Każdy ciąg na tej liście musi zawierać względną ścieżkę do zasobu w katalogu głównym rozszerzenia. Ukośniki wiodące („/”) są przycięty automatycznie.
run_at RunAt Opcjonalne. Określa, kiedy skrypt powinien zostać wstawiony na stronie. Domyślna wartość to document_idle
match_about_blank wartość logiczna Opcjonalne. Określa, czy skrypt powinien wstrzykiwać się w ramce about:blank gdzie ramka nadrzędna lub otwierająca pasuje do jednego ze wzorów zadeklarowanych w matches Wartość domyślna to fałsz.
match_origin_as_fallback wartość logiczna Opcjonalne. Określa, czy skrypt ma wstrzykiwać klatki, utworzone przez pasujące źródło, ale którego adres URL lub źródło może nie być bezpośrednio do wzorca. Obejmuje to ramki o różnych schematach, takich jak about:, data:, blob: i filesystem: Zobacz też Wstrzyknięcie w powiązanych ramkach
world ExecutionWorld Opcjonalne. Świat JavaScriptu, w którym skrypt ma zostać wykonany. Domyślna wartość to ISOLATED. Zobacz też Praca w odizolowanych światach.

Wstrzykiwanie z deklaracjami dynamicznymi

Skrypty treści dynamicznych są przydatne, gdy wzorce dopasowania skryptów treści są nie są dobrze znane lub gdy skrypty treści nie zawsze powinny być wstrzykiwane na znanych hostach.

Wprowadzone w Chrome 96 deklaracje dynamiczne są podobne do statycznych , ale obiekt skryptu content jest zarejestrowany w Chrome przy użyciu klucza w przestrzeni nazw chrome.scripting, a nie w manifest.json. Interfejs Scripting API umożliwia też programistom rozszerzeń do:

Podobnie jak deklaracje statyczne, deklaracje dynamiczne mogą zawierać pliki JavaScript, CSS lub oba te elementy.

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

Wstrzykiwanie automatycznie

Korzystaj z automatycznego wstrzykiwania w przypadku skryptów treści, które muszą być uruchamiane w odpowiedzi na zdarzenia lub w określonych miejscach do różnych okazji.

Aby można było automatycznie wstrzykiwać skrypt treści, rozszerzenie musi mieć uprawnienia hosta dla: stronie, na której próbuje wstrzyknąć skrypty. Uprawnienia hosta mogą być przyznane przez wysyła je w pliku manifestu rozszerzenia lub tymczasowo za pomocą "activeTab".

Poniżej znajdziesz różne wersje rozszerzenia ActiveTab.

manifest.json:

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

Skrypty treści można wstrzykiwać jako pliki.

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

Treść funkcji można też wstrzykiwać i wykonywać jako skrypt treści.

service-worker.js:

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

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

Pamiętaj, że wstrzyknięta funkcja jest kopią funkcji, do której odwołuje się funkcja chrome.scripting.executeScript(), a nie samą funkcję. W efekcie funkcja ciało musi być nieograniczone; odwołania do zmiennych spoza funkcji spowodują, że treść skrypt ReferenceError.

Podczas wstrzykiwania jako funkcji możesz też przekazywać do niej argumenty.

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

Wyklucz dopasowania i glory

Aby dostosować określone dopasowanie strony, uwzględnij w deklaracji następujące pola rejestracji.

Nazwa Typ Opis
exclude_matches tablica ciągów Opcjonalne. Wyklucza strony, które w innym przypadku zostałby wstrzykiwany przez ten skrypt treści . Szczegółowe informacje o składni wyrażeń znajdziesz w artykule Wzorce dopasowania. tych strun.
include_globs tablica ciągów Opcjonalne. Stosowane po matches, aby uwzględnić tylko te adresy URL, które zawierają też do tego globa. Ma na celu emulację interfejsu @include Słowo kluczowe Greasemonkey.
exclude_globs tablica ciągu znaków Opcjonalne. Stosowane po matches, aby wykluczyć adresy URL, które pasują do tego ustawienia glob. Służy do emulacji interfejsu @exclude Słowo kluczowe Greasemonkey.

Skrypt treści zostanie wstawiony na stronie, jeśli są spełnione oba te warunki:

  • Jego adres URL pasuje do dowolnego wzorca matches i dowolnego wzorca include_globs.
  • Adres URL nie pasuje również do wzorca exclude_matches ani exclude_globs. Ponieważ wymagana jest właściwość matches, exclude_matches, include_globs i exclude_globs może jedynie służyć do ograniczenia stron, których on dotyczy.

To rozszerzenie wstawia skrypt treści do klucza https://www.nytimes.com/health ale nie w 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" ],
}]);

Właściwości glob mają inną, bardziej elastyczną składnię niż wzorce dopasowania. Dopuszczalny wzorzec glob ciągi to adresy URL, które mogą zawierać symbole wieloznaczne gwiazdek i znaków zapytania. Gwiazdka (*) pasuje do dowolnego ciągu o dowolnej długości, w tym do pustego ciągu, a znak zapytania (?) pasuje do dowolnego znaku.

Na przykład wzorzec glob https://???.example.com/foo/\* pasuje do dowolnego z tych elementów:

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

Te dane nie są jednak zgodne z tymi:

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

To rozszerzenie wstawia skrypt treści do języków https://www.nytimes.com/arts/index.html i https://www.nytimes.com/jobs/index.htm*, ale nie w 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"]
    }
  ],
  ...
}

To rozszerzenie wstawia skrypt treści do języków https://history.nytimes.com i https://.nytimes.com/history, ale nie w: https://science.nytimes.com ani https://www.nytimes.com/science:

manifest.json

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

Aby uzyskać odpowiedni zakres, możesz uwzględnić jeden, wszystkie lub niektóre z nich.

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

Czas trwania

Pole run_at określa, kiedy pliki JavaScript są wstrzykiwane do strony internetowej. Preferowane i wartość domyślna to "document_idle". Sprawdź typ RunAt, aby poznać inne możliwe wartości. .

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" ],
}]);
Nazwa Typ Opis
document_idle ciąg znaków Preferowana. W miarę możliwości używaj "document_idle".

Przeglądarka wybiera czas wstrzykiwania skryptów między "document_end" a natychmiast po window.onload pożary zdarzeń. Dokładny moment wstrzyknięcia zależy od tego, jak złożony jest dokument i w jaki sposób długo się wczytuje i jest zoptymalizowana pod kątem szybkości wczytywania strony.

Skrypty treści uruchomione w "document_idle", nie muszą nasłuchiwać window.onload, jest gwarantowane po zakończeniu tworzenia DOM. Jeśli musi być uruchomiony po window.onload, rozszerzenie może sprawdzić, czy onload uruchomiono już przy użyciu instancji document.readyState usłudze.
document_start ciąg znaków Skrypty są wstrzykiwane po plikach z css, ale przed innymi elementami DOM lub uruchomić dowolny inny skrypt.
document_end ciąg znaków Skrypty są wstrzykiwane bezpośrednio po zakończeniu tworzenia DOM, ale przed zasobami podrzędnymi, takimi jak Zdjęcia i ramki zostały wczytane.

Określ ramki

Pole "all_frames" umożliwia rozszerzeniu określenie, czy pliki JavaScript i CSS powinny być jest wstrzyknięta we wszystkich ramkach spełniających określone wymagania dotyczące adresów URL lub tylko w najwyższej klatki w .

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" ],
}]);
Nazwa Typ Opis
all_frames wartość logiczna Opcjonalne. Domyślna wartość to false, co oznacza, że tylko górna klatka dopasowane.

Jeśli jest określony parametr true, zostaną wstrzyknięte wszystkie klatki, nawet jeśli parametr nie jest to najwyższa klatka na karcie. Każda ramka jest sprawdzana niezależnie pod kątem adresu URL . Nie będzie on wstrzyknięty do ramek podrzędnych, jeśli wymagania dotyczące adresów URL nie zostaną spełnione.

Rozszerzenia mogą chcieć uruchamiać skrypty w ramkach powiązanych z dopasowaniem ale nie do siebie pasują. Częstym scenariuszem jest to, dla ramek z adresami URL, które zostały utworzone przez pasującą ramkę, ale których adresy URL do określonych wzorców skryptu.

Dzieje się tak, gdy rozszerzenie chce wstrzykiwać ramki z adresami URL mają schematy about:, data:, blob: i filesystem:. W takich przypadkach Adres URL nie jest zgodny ze wzorcem skryptu treści (oraz w przypadku ciągu about: oraz data:, nie umieszczaj w adresie URL nadrzędnego adresu URL ani źródła na przykład about:blank czy data:text/html,<html>Hello, World!</html>). Takie klatki mogą jednak nadal być powiązane z ramką tworzącą.

Aby wstrzykiwać do tych ramek, rozszerzenia mogą określać właściwość "match_origin_as_fallback" w specyfikacji skryptu treści w parametrze pliku manifestu.

manifest.json

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

Gdy podasz wartość true i ustawisz wartość true, Chrome sprawdzi pochodzenie inicjator ramki, by określić, czy klatka pasuje, a nie w adresu URL ramki. Może się ono różnić od atrybutu origin ramki docelowej (np. data: adresów URL ma wartość null).

Inicjator ramki to ramka, która utworzyła element docelowy lub przemieszczała się po nim ramki. Choć jest to zwykle bezpośrednia decyzja nadrzędna lub otwierająca, niekoniecznie (jak w przypadku w przypadku ramki poruszającej się po elemencie iframe w elemencie iframe).

Porównuje to pochodzenie ramki inicjatora, może znajdować się na dowolnej ścieżce z tego punktu początkowego. Aby wyraźnie podkreślić to znaczenie, Chrome wymaga skryptów treści określonych za pomocą parametru "match_origin_as_fallback" ustaw na true, aby określić także ścieżkę *.

Jeśli określisz zarówno "match_origin_as_fallback", jak i "match_about_blank", "match_origin_as_fallback" ma wyższy priorytet.

Komunikacja ze stroną umieszczania

Mimo że środowiska wykonawcze skryptów treści i strony, na których je znajdują, są odizolowane uzyskują one dostęp do modelu DOM strony. Jeśli strona chce komunikować się z skrypt treści lub wraz z rozszerzeniem za pomocą skryptu dotyczącego treści, musi to robić za pośrednictwem wspólnego modelu DOM.

Przykładem może być 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);

Strona bez rozszerzeń (example.html) publikuje wiadomości w sobie. Ta wiadomość została przechwycona i sprawdzone przez skrypt treści, a następnie opublikowane w procesie rozszerzenia. W ten sposób strona ustanawia linię komunikacji z procesem przedłużania terminu. Odwrotność jest możliwa dzięki w podobny sposób.

Dostęp do plików rozszerzeń

Aby uzyskać dostęp do pliku rozszerzenia ze skryptu treści, możesz wywołać chrome.runtime.getURL(), aby uzyskać bezwzględny URL komponentu rozszerzenia zgodnie z tym przykładem (content.js):

content-script.js

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

Aby użyć czcionek lub obrazów w pliku CSS, możesz użyć @@extension_id do utworzenia adresu URL w sposób opisany w tym przykładzie (content.css):

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

W pliku manifest.json wszystkie zasoby muszą być zadeklarowane jako zasoby dostępne w internecie:

manifest.json

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

Dbaj o bezpieczeństwo

Izolowane światy zapewniają warstwę ochrony, ale skrypty treści mogą luki w zabezpieczeniach rozszerzenia i strony internetowej. Jeśli skrypt treści otrzymuje treści z tagu oddzielnej witryny, np. wywołując metodę fetch(), pamiętaj, aby filtrować treści według cross-site scripting, zanim go wstrzykniesz. Komunikuj się tylko przez HTTPS, aby: unikaj ataków typu &quot;man-in-the-middle&quot;.

Pamiętaj, aby odfiltrować złośliwe strony internetowe. Na przykład te wzorce są niebezpieczne i niedozwolone w pliku manifestu w wersji 3:

Nie

content-script.js

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

content-script.js

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

Zamiast tego korzystaj z bezpieczniejszych interfejsów API, które nie uruchamiają skryptów:

Tak

content-script.js

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

content-script.js

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