From c9056ef21f223e435051806a9b48933c92ad6545 Mon Sep 17 00:00:00 2001 From: Erick Zhao Date: Wed, 17 Aug 2022 15:36:34 -0700 Subject: [PATCH 1/4] docs: update E20 sandbox rendering defaults --- docs/tutorial/sandbox.md | 76 ++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/docs/tutorial/sandbox.md b/docs/tutorial/sandbox.md index db71727efb6cc..6cfcc94979056 100644 --- a/docs/tutorial/sandbox.md +++ b/docs/tutorial/sandbox.md @@ -12,28 +12,8 @@ the GPU service and the network service. See Chromium's [Sandbox design document][sandbox] for more information. -## Electron's sandboxing policies - -Electron comes with a mixed sandbox environment, meaning sandboxed processes can run -alongside privileged ones. By default, renderer processes are not sandboxed, but -utility processes are. Note that as in Chromium, the main (browser) process is -privileged and cannot be sandboxed. - -Historically, this mixed sandbox approach was established because having Node.js available -in the renderer is an extremely powerful tool for app developers. Unfortunately, this -feature is also an equally massive security vulnerability. - -Theoretically, unsandboxed renderers are not a problem for desktop applications that -only display trusted code, but they make Electron less secure than Chromium for -displaying untrusted web content. However, even purportedly trusted code may be -dangerous — there are countless attack vectors that malicious actors can use, from -cross-site scripting to content injection to man-in-the-middle attacks on remotely loaded -websites, just to name a few. For this reason, we recommend enabling renderer sandboxing -for the vast majority of cases under an abundance of caution. - - -Note that there is an active discussion in the issue tracker to enable renderer sandboxing -by default. See [#28466][issue-28466]) for details. +**As of Electron 20, all renderer and utility processes in Electron are sandboxed by default.** +**As in Chromium, the main (browser) process is privileged and cannot be sandboxed.** ## Sandbox behaviour in Electron @@ -46,12 +26,17 @@ When renderer processes in Electron are sandboxed, they behave in the same way a regular Chrome renderer would. A sandboxed renderer won't have a Node.js environment initialized. - Therefore, when the sandbox is enabled, renderer processes can only perform privileged tasks (such as interacting with the filesystem, making changes to the system, or spawning subprocesses) by delegating these tasks to the main process via inter-process communication (IPC). +:::note + +For more info on inter-process communication, check out our [IPC guide](./ipc.md). + +::: + ### Preload scripts In order to allow renderer processes to communicate with the main process, preload @@ -83,13 +68,21 @@ privileged APIs to untrusted code running in the renderer process unless ## Configuring the sandbox -### Enabling the sandbox for a single process +It is possible to disable the renderer sandbox on a per-process basis. +Theoretically, unsandboxed renderers are not a problem for desktop applications that +only display trusted code, but they make Electron less secure than Chromium for +displaying untrusted web content. However, even purportedly trusted code may be +dangerous — there are countless attack vectors that malicious actors can use, from +cross-site scripting to content injection to man-in-the-middle attacks on remotely loaded +websites, just to name a few. For this reason, we recommend enabling renderer sandboxing +for the vast majority of cases under an abundance of caution. + +### Disabling the sandbox for a single process -In Electron, renderer sandboxing can be enabled on a per-process basis with -the `sandbox: true` preference in the [`BrowserWindow`][browser-window] constructor. +In Electron, renderer sandboxing can be disabled on a per-process basis with +the `sandbox: false` preference in the [`BrowserWindow`][browser-window] constructor. -```js -// main.js +```js title='main.js' app.whenReady().then(() => { const win = new BrowserWindow({ webPreferences: { @@ -100,17 +93,32 @@ app.whenReady().then(() => { }) ``` +Sandboxing is also disabled whenever Node.js integration is enabled in the renderer. +This can be done through the BrowserWindow constructor with the `contextIsolation: false` +and `nodeIntegration: true` flags: + +```js title='main.js' +app.whenReady().then(() => { + const win = new BrowserWindow({ + webPreferences: { + contextIsolation: false, + nodeIntegration: true + } + }) + win.loadURL('https://google.com') +}) +``` + ### Enabling the sandbox globally If you want to force sandboxing for all renderers, you can also use the [`app.enableSandbox`][enable-sandbox] API. Note that this API has to be called before the app's `ready` event. -```js -// main.js +```js title='main.js' app.enableSandbox() app.whenReady().then(() => { - // no need to pass `sandbox: true` since `app.enableSandbox()` was called. + // any sandbox:false calls are overridden since `app.enableSandbox()` was called. const win = new BrowserWindow() win.loadURL('https://google.com') }) @@ -139,16 +147,16 @@ issues: have, to inherit everything we can from Chromium, and to respond quickly to security issues, but Electron cannot be as secure as Chromium without the resources that Chromium is able to dedicate. -2. Some security features in Chrome (such as Safe Browsing and Certificate +1. Some security features in Chrome (such as Safe Browsing and Certificate Transparency) require a centralized authority and dedicated servers, both of which run counter to the goals of the Electron project. As such, we disable those features in Electron, at the cost of the associated security they would otherwise bring. -3. There is only one Chromium, whereas there are many thousands of apps built +1. There is only one Chromium, whereas there are many thousands of apps built on Electron, all of which behave slightly differently. Accounting for those differences can yield a huge possibility space, and make it challenging to ensure the security of the platform in unusual use cases. -4. We can't push security updates to users directly, so we rely on app vendors +1. We can't push security updates to users directly, so we rely on app vendors to upgrade the version of Electron underlying their app in order for security updates to reach users. From 635eb3312ffde2f7eb06b0515db74194b66a156d Mon Sep 17 00:00:00 2001 From: Erick Zhao Date: Thu, 18 Aug 2022 10:48:48 -0700 Subject: [PATCH 2/4] docs: update tutorial --- docs/tutorial/sandbox.md | 2 +- docs/tutorial/tutorial-3-preload.md | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/docs/tutorial/sandbox.md b/docs/tutorial/sandbox.md index 6cfcc94979056..83958751d578a 100644 --- a/docs/tutorial/sandbox.md +++ b/docs/tutorial/sandbox.md @@ -51,7 +51,7 @@ but can only import a subset of Electron and Node's built-in modules: In addition, the preload script also polyfills certain Node.js primitives as globals: -* [`Buffer`](https://nodejs.org/api/Buffer.html) +* [`Buffer`](https://nodejs.org/api/buffer.html) * [`process`](../api/process.md) * [`clearImmediate`](https://nodejs.org/api/timers.html#timers_clearimmediate_immediate) * [`setImmediate`](https://nodejs.org/api/timers.html#timers_setimmediate_callback_args) diff --git a/docs/tutorial/tutorial-3-preload.md b/docs/tutorial/tutorial-3-preload.md index 6f84cfe421909..80e12ef0e82d7 100644 --- a/docs/tutorial/tutorial-3-preload.md +++ b/docs/tutorial/tutorial-3-preload.md @@ -38,7 +38,25 @@ called a **preload**. ## Augmenting the renderer with a preload script A BrowserWindow's preload script runs in a context that has access to both the HTML DOM -and a Node.js environment. Preload scripts are injected before a web page loads in the renderer, +and a limited subset of Node.js and Electron APIs. + +:::info Preload script sandboxing + +From Electron 20 onwards, preload scripts are **sandboxed** by default and no longer have access +to a full Node.js environment. Practically, this means that you have a polyfilled `require` +function that only has access to a limited set of APIs. + +| Available API | Details | +| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Electron modules | Renderer process modules | +| Node.js modules | [`events`](https://nodejs.org/api/events.html), [`timers`](https://nodejs.org/api/timers.html), [`url`](https://nodejs.org/api/url.html) | +| Polyfilled globals | [`Buffer`](https://nodejs.org/api/buffer.html), [`process`](../api/process.md), [`clearImmediate`](https://nodejs.org/api/timers.html#timers_clearimmediate_immediate), [`setImmediate`](https://nodejs.org/api/timers.html#timers_setimmediate_callback_args) | + +For more information, check out the [Process Sandboxing](./sandbox.md) guide. + +::: + +Preload scripts are injected before a web page loads in the renderer, similar to a Chrome extension's [content scripts][content-script]. To add features to your renderer that require privileged access, you can define [global] objects through the [contextBridge][contextbridge] API. From 8411bdd40f057c8cfc16d10af326c5969c90615e Mon Sep 17 00:00:00 2001 From: Erick Zhao Date: Tue, 6 Sep 2022 16:34:09 -0700 Subject: [PATCH 3/4] simplify paragraph --- docs/tutorial/sandbox.md | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/docs/tutorial/sandbox.md b/docs/tutorial/sandbox.md index 83958751d578a..69f2522cbfec9 100644 --- a/docs/tutorial/sandbox.md +++ b/docs/tutorial/sandbox.md @@ -12,8 +12,10 @@ the GPU service and the network service. See Chromium's [Sandbox design document][sandbox] for more information. -**As of Electron 20, all renderer and utility processes in Electron are sandboxed by default.** -**As in Chromium, the main (browser) process is privileged and cannot be sandboxed.** +Starting from Electron 20, the sandbox is enabled for renderer processes without any +further configuration. If you want to disable the sandbox for a process, see the +[Disabling the sandbox for a single process](#disabling-the-sandbox-for-a-single-process) +section. ## Sandbox behaviour in Electron @@ -68,14 +70,10 @@ privileged APIs to untrusted code running in the renderer process unless ## Configuring the sandbox -It is possible to disable the renderer sandbox on a per-process basis. -Theoretically, unsandboxed renderers are not a problem for desktop applications that -only display trusted code, but they make Electron less secure than Chromium for -displaying untrusted web content. However, even purportedly trusted code may be -dangerous — there are countless attack vectors that malicious actors can use, from -cross-site scripting to content injection to man-in-the-middle attacks on remotely loaded -websites, just to name a few. For this reason, we recommend enabling renderer sandboxing -for the vast majority of cases under an abundance of caution. +For most apps, sandboxing is the best choice. In certain use cases that are incompatible with +the sandbox (for instance, when using native node modules in the renderer), +it is possible to disable the sandbox for specific processes. This comes with security +risks, especially if any untrusted code or content is present in the unsandboxed process. ### Disabling the sandbox for a single process From ec9f471cceee32480ec02bbe479be07aa43f099b Mon Sep 17 00:00:00 2001 From: Erick Zhao Date: Wed, 7 Sep 2022 11:15:29 -0700 Subject: [PATCH 4/4] dont mention context isolation --- docs/tutorial/sandbox.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/tutorial/sandbox.md b/docs/tutorial/sandbox.md index 69f2522cbfec9..5081d557ba0db 100644 --- a/docs/tutorial/sandbox.md +++ b/docs/tutorial/sandbox.md @@ -92,14 +92,12 @@ app.whenReady().then(() => { ``` Sandboxing is also disabled whenever Node.js integration is enabled in the renderer. -This can be done through the BrowserWindow constructor with the `contextIsolation: false` -and `nodeIntegration: true` flags: +This can be done through the BrowserWindow constructor with the `nodeIntegration: true` flag. ```js title='main.js' app.whenReady().then(() => { const win = new BrowserWindow({ webPreferences: { - contextIsolation: false, nodeIntegration: true } })