Electron contextIsolation + Preload Security Pattern
Problem
With nodeIntegration: true, the renderer (webpage) can directly access the filesystem via require('fs'). If loading external URLs, this is a critical security risk.
Solution
// main.js
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true, // separate renderer and Node.js contexts
nodeIntegration: false, // block require in renderer
}
});
// preload.js - bridge between main and renderer
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
scanNetwork: () => ipcRenderer.invoke('scan-network'),
getVersion: () => ipcRenderer.invoke('get-version'),
onScanResult: (callback) =>
ipcRenderer.on('scan-result', (_, data) => callback(data)),
});
// renderer.js - use in the webpage
const results = await window.electronAPI.scanNetwork();
Key Points
- With
contextIsolation: true, the preload script’s globals and the renderer’s globals are completely separate. Only functions exposed viacontextBridge.exposeInMainWorldare accessible. - The renderer can only use what’s defined in
window.electronAPI. Dangerous access likerequire('child_process')is impossible. ipcRenderer.invokereturns a Promise for bidirectional communication. Handle it in the main process withipcMain.handle.