sandbox
| Typ | Object |
|---|---|
| Erforderlich | Nein |
| Manifest-Version | 2 oder höher |
| Beispiel |
json |
Verwenden Sie den Schlüssel sandbox, um eine oder mehrere Seiten einer Erweiterung als isolierte Seiten zu kennzeichnen.
Isolierte Seiten werden mit einem einzigartigen, undurchsichtigen Ursprung geladen, anstelle des üblichen moz-extension:// Ursprungs der Erweiterung. Infolgedessen:
- Isolierte Seiten können nicht auf WebExtension-APIs zugreifen. Die globalen Objekte
browserundchromesind nicht verfügbar. - Isolierte Seiten können nicht auf andere Seiten innerhalb der Erweiterung zugreifen, noch von diesen erreicht werden. Sie können jedoch indirekt über APIs wie
Window.postMessage()kommunizieren. - Web-Plattform-APIs, die an den Ursprung gebunden sind, sind nicht verfügbar. Beispiele hierfür finden Sie im
allow-same-origin-Wert derContent-Security-Policy: sandbox-Direktive.
Einer isolierten Seite kann eine flexiblere Content-Security-Policy (CSP) zugewiesen werden als dem Rest der Erweiterung. Dies schließt eine CSP ein, die eval() und ähnliche Konstrukte erlaubt, die durch die Standard-Content-Security-Policy einer Erweiterung blockiert werden. Da eine isolierte Seite keine WebExtension-APIs verwenden oder direkt auf den Rest der Erweiterung zugreifen kann, kann dies ohne Beeinträchtigung der Gesamtsicherheit der Erweiterung erfolgen.
Dies macht den sandbox-Schlüssel nützlich für Code, der eval() oder ähnliche Konstrukte benötigt. Laden Sie den Code in einer isolierten Seite und verwenden Sie postMessage(), um Daten an den Rest der Erweiterung zu senden und Ergebnisse zurückzuerhalten.
Syntax
sandbox ist ein Objekt mit diesen Eigenschaften:
pages- Erforderlich. Ein Array von Strings. Eine Liste von Pfaden, relativ zu manifest.json, zu den isolierten Seiten der Erweiterung.
content_security_policy-
Optional. Ein String. Nur Manifest V2. Die auf die isolierten Seiten angewendete Content-Security-Policy. Für das Manifest V3-Äquivalent siehe die
sandbox-Eigenschaft descontent_security_policy-Schlüssels, beschrieben in Content-Security-Policy für isolierte Seiten.
Content-Security-Policy für isolierte Seiten
In Manifest V3 wird die Content-Security-Policy für isolierte Seiten mittels der sandbox-Eigenschaft des content_security_policy-Schlüssels gesetzt. Diese Eigenschaft ist nur für Manifest V3. In Manifest V2 verwenden Sie stattdessen die content_security_policy-Eigenschaft des sandbox-Schlüssels.
Wenn keine Policy angegeben wird, erhalten isolierte Seiten diese Standard-Content-Security-Policy:
sandbox allow-scripts; script-src 'self';
Dies isoliert eine isolierte Seite vom Rest der Erweiterung und erlaubt kein eval() oder ähnliche Konstrukte.
Um zum Beispiel die CSP zu individualisieren, um eval() in sandbox.html zu ermöglichen, fügen Sie 'unsafe-eval' hinzu, wie folgt:
// Manifest V3
"sandbox": {
"pages": ["sandbox.html"]
},
"content_security_policy": {
"sandbox": "sandbox allow-scripts; script-src 'self' 'unsafe-eval';"
}
// Manifest V2
"sandbox": {
"pages": ["sandbox.html"],
"content_security_policy": "sandbox allow-scripts; script-src 'self' 'unsafe-eval';"
}
Jede angepasste Policy für isolierte Seiten muss diese Anforderungen erfüllen:
Beste Praktiken
Bei der Verwendung einer isolierten Seite sollten Sie diese besten Praktiken beachten:
-
Validieren Sie Nachrichten. Wenn eine isolierte Seite mit dem Rest der Erweiterung über
Window.postMessage()kommuniziert, ist sie denselben Risiken ausgesetzt wie jede andere Verwendung vonpostMessage(). Überprüfen Sie den Ursprung und die Struktur jeder Nachricht, bevor Sie darauf reagieren. Siehe Sicherheitsbedenken in derpostMessage()-Dokumentation.Der
location.origineiner isolierten Seite spiegelt denmoz-extension://-Ursprung der Erweiterung wider. Daher kann eine isolierte Seite eine eingehende Nachricht validieren, indem sie überprüft, obevent.originmitlocation.originübereinstimmt.Nachrichten, die von einer isolierten Seite gesendet werden, melden die Serialisierung des undurchsichtigen Ursprungs (
"null"), der von anderen undurchsichtigen Ursprüngen nicht unterscheidbar ist. Daher kann die Erweiterungsseite, die die Nachrichten empfängt, nicht durch den Ursprung validieren; statt dessen vergleichen Sieevent.sourcemit demcontentWindowdes isolierten Frames.Das bedeutet, dass es beim Posten einer Nachricht an eine isolierte Seite keinen spezifischen Ursprung gibt, auf den gezielt werden kann, da ihr undurchsichtiger Ursprung nicht als Zielursprung-String ausgedrückt werden kann. Die übliche
postMessage()-Best Practice, einen spezifischen Ursprung anzuvisieren, kann hier nicht verfolgt werden; verwenden Sie stattdessen"*". Es gibt keine Alternative, bis dieses Spezifikationsproblem gelöst ist. -
Führen Sie keinen nicht vertrauenswürdigen Code aus. Obwohl eine isolierte Seite keine WebExtension-APIs verwenden kann, identifiziert ihre
moz-extension://-URL die Erweiterung. Daher könnte nicht vertrauenswürdiger Code, der in der Sandbox ausgeführt wird, verwendet werden, um die Erweiterung oder ihren Benutzer zu identifizieren. -
Entspannen Sie die CSP nicht nur um WebAssembly zu aktivieren. Wenn WebAssembly-Unterstützung der einzige Grund für die Verwendung einer isolierten Seite ist, fügen Sie
'wasm-unsafe-eval'zurcontent_security_policyder Erweiterung hinzu, anstatt die CSP einer isolierten Seite zu lockern.
Beispiel
Dieses Beispiel wertet einen mathematischen Ausdruck in einer isolierten Seite aus und gibt das Ergebnis an das Popup der Erweiterung zurück.
manifest.json:
{
"manifest_version": 3,
"name": "Sandbox calculator example",
"version": "1.0",
"action": {
"default_popup": "popup.html"
},
"sandbox": {
"pages": ["sandbox.html"]
},
"content_security_policy": {
"sandbox": "sandbox allow-scripts; script-src 'self' 'unsafe-eval';"
}
}
sandbox.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<script src="sandbox.js"></script>
</head>
<body></body>
</html>
sandbox.js horcht auf Nachrichten vom Popup, wertet den Ausdruck aus und sendet das Ergebnis zurück. Es validiert die Nachricht, indem es event.origin mit seinem location.origin vergleicht, welcher den Ursprung der Erweiterung widerspiegelt:
window.addEventListener("message", (event) => {
if (event.origin !== location.origin) {
// Reject messages not coming from the extension.
return;
}
event.source.postMessage(eval(event.data), event.origin);
});
popup.html bettet die isolierte Seite nicht direkt ein; das iframe wird von popup.js erstellt:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
</head>
<body>
<input id="expression" value="1 + 2" />
<button id="calculate">Calculate</button>
<div id="result"></div>
<script src="popup.js"></script>
</body>
</html>
popup.js erstellt das isolierte iframe und fügt einen Nachrichtenlistener hinzu, bevor es an das Dokument angefügt wird, damit keine Antwort verpasst wird:
async function runCalculation(expression) {
const iframe = document.createElement("iframe");
iframe.src = "sandbox.html";
iframe.hidden = true;
await new Promise((resolve) => {
iframe.addEventListener("load", resolve, { once: true });
document.body.append(iframe);
});
const reply = new Promise((resolve) => {
const handleMessage = (event) => {
if (event.source !== iframe.contentWindow) {
return;
}
window.removeEventListener("message", handleMessage);
resolve(event.data);
};
window.addEventListener("message", handleMessage);
});
// Best practice is to target a specific origin instead of "*",
// but a sandboxed page has an opaque origin ("null"), so there's
// no specific origin to target.
iframe.contentWindow.postMessage(expression, "*");
const result = await reply;
iframe.remove();
return result;
}
document.getElementById("calculate").addEventListener("click", async () => {
const expression = document.getElementById("expression").value;
document.getElementById("result").textContent =
await runCalculation(expression);
});