Fähigkeiten und Sicherheit

Auf dieser Seite

Sandboxed Plugins sind standardmäßig isoliert. Um über das Lesen und Schreiben des eigenen KV und Storage hinauszugehen, muss ein Plugin eine Fähigkeit in seinem Manifest deklarieren. Die Sandbox-Bridge kontrolliert jede vom Host bereitgestellte API basierend auf diesen Deklarationen — ein Plugin, das content:read nicht deklariert hat, erhält kein ctx.content, und eines ohne network:request erhält kein ctx.http.

Diese Seite behandelt, was jede Fähigkeit gewährt, wie die Sandbox sie durchsetzt und was nicht durchsetzbar ist.

Fähigkeiten deklarieren

Fähigkeiten befinden sich in emdash-plugin.jsonc, neben slug und dem Rest des Vertrauensvertrags:

{
	"slug": "plugin-hello",
	// ...identity + profile...

	"capabilities": ["content:read", "network:request"],
	"allowedHosts": ["api.example.com"]
}

Deklarieren Sie nur, was das Plugin tatsächlich benötigt. Fähigkeitsdeklarationen sind auch das, was der Marketplace Site-Betreibern im Zustimmungsdialog anzeigt — zusätzliche Fähigkeiten sind Reibung bei der Installation und ein Sicherheitsflag bei Audits.

Fähigkeitsreferenz

FähigkeitGewährt Zugriff auf
content:readctx.content.get(), ctx.content.list()
content:writectx.content.create(), ctx.content.update(), ctx.content.delete() (impliziert content:read)
media:readctx.media.get(), ctx.media.list()
media:writectx.media.getUploadUrl(), ctx.media.upload(), ctx.media.delete() (impliziert media:read)
network:requestctx.http.fetch() — beschränkt auf allowedHosts
network:request:unrestrictedctx.http.fetch() ohne Host-Beschränkung (nur für benutzerkonfigurierte URLs)
users:readctx.users.get(), ctx.users.getByEmail(), ctx.users.list()
email:sendctx.email.send() (erfordert ein konfiguriertes E-Mail-Provider-Plugin)
hooks.email-transport:registerErlaubt die Registrierung des exklusiven email:deliver-Hooks (Transport-Provider)
hooks.email-events:registerErlaubt die Registrierung von email:beforeSend / email:afterSend-Hooks
hooks.page-fragments:registerErlaubt die Registrierung des page:fragments-Hooks (nur native Plugins)

Einige Dinge, die Sie wissen sollten:

  • Implikationen. content:write impliziert automatisch content:read; media:write impliziert media:read; network:request:unrestricted impliziert network:request. Sie müssen nicht beide auflisten.
  • network:request:unrestricted existiert für benutzerkonfigurierte URLs. Ein Webhook-Plugin, bei dem der Betreiber die Ziel-URL eingibt, muss Hosts erreichen können, die nicht im Manifest stehen. Plugins, die immer bekannte APIs aufrufen, sollten network:request + allowedHosts verwenden.
  • email:send wird durch Konfiguration gegated, nicht nur durch die Fähigkeit. Ein Plugin kann email:send deklarieren, aber ctx.email wird nur befüllt, wenn ein anderes Plugin einen email:deliver-Transport registriert hat.

Netzwerk-Host-Allowlists

Plugins mit network:request können nur Hosts abrufen, die in allowedHosts aufgeführt sind. Wildcards werden für Subdomains unterstützt:

"capabilities": ["network:request"],
"allowedHosts": [
	"api.example.com",     // exact host
	"*.cdn.example.com"    // any subdomain of cdn.example.com
]

Die Bridge prüft den Host der Anfrage-URL gegen die Allowlist, bevor die Anfrage weitergeleitet wird. Eine Anfrage an einen nicht deklarierten Host wirft innerhalb des Plugins, ohne die Sandbox jemals zu verlassen.

network:request:unrestricted überspringt die Allowlist-Prüfung vollständig. Es ist für Plugins gedacht, bei denen der Betreiber die Ziel-URL zur Laufzeit konfiguriert (Webhook-Sender, generische HTTP-Weiterleiter). Vermeiden Sie es für Plugins, bei denen das Ziel Teil des Plugin-Designs ist — deklarieren Sie stattdessen network:request mit expliziten Hosts, damit der Zustimmungsdialog den Betreibern genau zeigt, wohin das Plugin Anfragen senden wird.

Was die Sandbox durchsetzt

Wenn ein Sandbox-Runner aktiv ist, setzt die Runtime durch:

  1. Fähigkeits-Gating. Die PluginContext-Factory befüllt ctx.content, ctx.media, ctx.http, ctx.users, ctx.email nur, wenn die entsprechende Fähigkeit deklariert ist. Das Aufrufen einer Methode auf einer nicht deklarierten Fähigkeit ist nicht möglich — es gibt kein Objekt dort.

  2. Storage- und KV-Scoping. Jede Storage- und KV-Operation ist auf den Slug des Plugins beschränkt. Ein Plugin kann nicht das KV oder die Storage-Collections eines anderen Plugins lesen und nur auf Storage-Collections zugreifen, die es im Manifest deklariert hat.

  3. Netzwerkisolation. Direktes fetch() und andere Netzwerk-Primitive werden vom Runner blockiert. Der einzige Weg zum Netzwerk ist ctx.http.fetch(), das durch die Host-Validierung der Bridge geht.

  4. Keine Host-Bindings. Sandboxed Plugins sehen keine Umgebungsvariablen, das Dateisystem oder Plattform-Bindings — auch wenn Ihr Host-Worker sie hat. Die Plugin-Runtime ist ein sauberes Isolate mit nur der Bridge und den deklarierten Fähigkeiten.

  5. Ressourcenlimits. Der Runner kann CPU-, Subrequest-, Wall-Clock- und Speicherlimits pro Aufruf durchsetzen. Die genauen Limits hängen davon ab, welchen Runner Sie verwenden; der Cloudflare-Runner verwendet die Worker Loader-Limits der Plattform (50ms CPU pro Aufruf, 10 Subrequests, 30 Sekunden Wall-Clock, ~128MB Speicher). Der Node.js workerd-Runner (@emdash-cms/sandbox-workerd) setzt Wall-Clock-Zeit über Promise.race durch; CPU- und Speicherlimits sind Cloudflare-Plattformfunktionen und werden von standalone workerd nicht durchgesetzt. Hooks, die die Limits des Runners überschreiten, werden abgebrochen; das EmDash-Hook-Timeout (timeout in der Hook-Konfiguration) setzt eine strengere Obergrenze darüber hinaus durch.

Was die Sandbox nicht durchsetzt

Einige Dinge, die das Fähigkeitssystem nicht abdeckt und nicht abdecken kann:

  • Verhalten innerhalb einer gewährten Fähigkeit. Ein Plugin mit content:write kann jeden Inhalt bearbeiten, nicht nur seinen eigenen. Fähigkeiten sind grob — sie sagen „dieses Plugin kann Inhalte schreiben“, nicht „dieses Plugin kann nur die von ihm erstellten Inhalte schreiben“. Audit-Zeit-Review ist die einzige Prüfung dessen, was ein Plugin tatsächlich innerhalb seiner Gewährung tut.
  • Operator-Vertrauen auf Node.js. Wenn der konfigurierte Sandbox-Runner als nicht verfügbar gemeldet wird (kein Cloudflare Worker Loader, kein Node-seitiger Runner installiert usw.), werden sandboxed: []-Plugins beim Start übersprungen. Sie können sie in plugins: [] verschieben, um sie im Prozess auszuführen — aber dann gibt es kein V8-Isolate, keine Ressourcenlimits, und das Plugin kann fetch() direkt aufrufen oder Umgebungsvariablen lesen. Behandeln Sie das als native Vertrauensstufe.
  • Nebenkanäle. Timing, Log-Ausgabe und gespeicherte Daten sind für jeden mit entsprechendem Zugriff auf die Host-Umgebung sichtbar. Verwenden Sie die Sandbox nicht als Vertraulichkeitsgrenze gegen den sie betreibenden Operator.

Fähigkeitszustimmung

Wenn ein Betreiber ein sandboxed Plugin vom Marketplace installiert, zeigt EmDash einen Zustimmungsdialog mit den deklarierten Fähigkeiten. Updates, die Fähigkeiten hinzufügen — zum Beispiel ein Plugin, das zuvor nur Inhalte las und jetzt Netzwerkanfragen stellen möchte — erscheinen als Fähigkeits-Diff und erfordern eine neue Genehmigung, bevor die neue Version wirksam wird.

Deshalb ist es wichtig, zusätzliche Fähigkeiten zu deklarieren, auch wenn Sie sie „später vielleicht brauchen“. Sie erscheinen als Reibung bei jeder Installation und jedem Update, und Sicherheitsaudits markieren Plugins, die mehr verlangen, als sie offensichtlich benötigen. Listen Sie genau auf, was das Plugin verwendet, und fügen Sie neue Fähigkeiten in einer echten Version hinzu, wenn das Plugin sie tatsächlich zu nutzen beginnt.

Bundle-Zeit-Validierung

emdash-plugin bundle und emdash-plugin publish führen zusätzliche Prüfungen durch:

  • Jede deklarierte Fähigkeit muss in der anerkannten Menge sein (Tippfehler führen zum Build-Fehler).
  • network:request erfordert eine nicht leere allowedHosts; network:request:unrestricted erfordert, dass sie leer ist. Siehe die Manifest-Referenz.
  • Das gebündelte backend.js darf keine Node.js-Built-ins importieren (fs, path, child_process usw.) — Sandbox-Runtimes stellen sie nicht bereit.

Siehe Bundling und Publishing für die vollständige Liste der Prüfungen.