Die Sandbox ist ein Sicherheits-Feature von Chromium, das Electron für Renderer-Prozesse nutzt: der Prozess läuft mit eingeschränkten OS-Berechtigungen und kann auch im Preload kein direktes Node-API mehr aufrufen. Default seit Electron 20, sollte fast immer aktiv bleiben.
Aktivierung
const win = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
sandbox: true, // explizit (Default seit v20)
contextIsolation: true,
nodeIntegration: false
}
});sandbox: true aktiviert die Sandbox für den Renderer und das Preload-Skript dieses Fensters.
Was die Sandbox einschränkt
Im Sandbox-Modus hat der Renderer-Prozess (und sein Preload):
| Bereich | Erlaubt | Verboten |
|---|---|---|
| Filesystem | Über IPC zum Main | Kein direktes fs |
| Child-Process | Über IPC | Kein child_process |
| Native Modules | Nein | Auch nicht im Preload |
| OS-Calls | Nur via Chromium-API | Keine direkten Syscalls |
| Web-APIs | Voll | — |
electron-Modul | Nur contextBridge, ipcRenderer, webFrame | Rest weg |
process-Variable | versions, platform, arch, pid | process.env, cwd() etc. |
Praktisch: jede Native-Operation läuft jetzt über IPC. Der Main hat den vollen Node-Zugriff und delegiert kontrolliert.
Warum das gut ist
Die Sandbox kombiniert zwei Sicherheits-Ebenen:
- JavaScript-Ebene: Preload kann keine Node-APIs mehr direkt aufrufen → kompromittierter Web-Code kann das auch nicht
- OS-Ebene: der Renderer-Prozess läuft mit reduzierten Berechtigungen — selbst bei einer Chromium-Schwachstelle kann der Angreifer das System nicht direkt manipulieren
Faustregel: ohne Sandbox bist du allein mit JavaScript-Mauern; mit Sandbox stehst du auf zwei Beinen.
Workflow mit Sandbox
Der typische Workflow im Sandbox-Modus:
import { contextBridge, ipcRenderer } from 'electron';
contextBridge.exposeInMainWorld('api', {
readFile: (p) => ipcRenderer.invoke('files:read', p),
writeFile: (p, c) => ipcRenderer.invoke('files:write', p, c),
execCmd: (cmd) => ipcRenderer.invoke('shell:exec', cmd)
});import fs from 'node:fs/promises';
import { execFile } from 'node:child_process';
ipcMain.handle('files:read', async (_event, path) => {
// Validierung!
if (!path.startsWith(app.getPath('userData'))) return null;
return fs.readFile(path, 'utf-8');
});
ipcMain.handle('shell:exec', async (_event, cmd) => {
// Whitelisting!
const allowed = ['ls', 'pwd'];
if (!allowed.includes(cmd)) return null;
return new Promise((res) => execFile(cmd, [], (_e, out) => res(out)));
});Der Preload ist eine dünne Bridge ohne Logik. Die echte Arbeit (mit Validierung) passiert im Main.
Wann Sandbox deaktivieren?
Realistisch gibt es zwei Szenarien:
- Legacy-Migration: alte Apps, die im Preload Node-APIs nutzen — Übergangsweise mit
sandbox: false, bis die Logik in den Main migriert ist. - Sehr spezifische Use-Cases: z. B. Browser-Erweiterungen, die intern Node nutzen müssen, ohne IPC-Roundtrip — sehr selten.
In allen anderen Fällen: aktiviert lassen. Die paar IPC-Calls mehr lohnen sich für das Sicherheits-Plus.
Sandbox + ESM
Seit Electron 28 funktioniert ESM auch im Sandbox-Preload. Vor 28: nur CommonJS. Wer also ein altes Projekt hochzieht und ESM-Preload haben will:
{
"type": "module"
}Plus Electron ≥ 28. Beides zusammen → moderne ESM-Syntax, volle Sandbox-Sicherheit.
FAQ
Ist Sandbox automatisch an?
Seit Electron 20 ist sandbox: true der empfohlene Default — bei explizitem webPreferences muss man's aber selbst setzen. Wer ohne webPreferences-Block ein Window erzeugt: Sandbox ist nicht automatisch an. Daher immer explizit angeben.
Was ist der Unterschied zu contextIsolation?
contextIsolation trennt Preload- und Web-Heap (JavaScript-Ebene). Sandbox läuft den Renderer in eingeschränkten OS-Berechtigungen (Prozess-Ebene) UND limitiert die Node-APIs im Preload. Beide sind separate Schutz-Layer — gemeinsam genutzt.
Welche electron-Imports gehen im Sandbox-Preload?
contextBridge, ipcRenderer, webFrame. Mehr nicht. Wer dialog, app etc. braucht: das geht nur im Main, der Preload muss per IPC delegieren.
Bricht Sandbox bestehende Web-Apps?
Nein — Web-APIs (DOM, fetch, localStorage etc.) funktionieren komplett. Was bricht: Code, der direkt require('fs') o. ä. im Renderer aufrief (was schon vor Sandbox keine gute Idee war).
Wie performant ist Sandbox?
Praktisch nicht messbar. IPC-Roundtrips kosten Mikrosekunden. In Hot-Paths mit zehntausenden Calls pro Sekunde könnte's auffallen — bei normalen Apps nicht.
Funktioniert Sandbox auf allen Plattformen gleich?
Auf Linux setzt Chromium auf das unprivileged_userns_clone-Feature. Auf manchen alten Distros oder unter bestimmten Container-Setups (Docker ohne --cap-add SYS_ADMIN) kann die Sandbox stören oder gar nicht starten. Pragmatisch: testen, dann ggf. mit --no-sandbox umgehen — für Distribution aber niemals.