From f5a70b2947ae0642ae40c84a7038d16013bec1f4 Mon Sep 17 00:00:00 2001 From: Milan Burda Date: Sun, 10 Mar 2019 10:16:33 +0100 Subject: [PATCH 1/3] docs: add remote module to docs/tutorial/security.md --- docs/tutorial/security.md | 119 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/docs/tutorial/security.md b/docs/tutorial/security.md index 27ec922ab1fe2..1f1b5aa597999 100644 --- a/docs/tutorial/security.md +++ b/docs/tutorial/security.md @@ -109,6 +109,8 @@ You should at least follow these steps to improve the security of your applicati 12. [Disable or limit navigation](#12-disable-or-limit-navigation) 13. [Disable or limit creation of new windows](#13-disable-or-limit-creation-of-new-windows) 14. [Do not use `openExternal` with untrusted content](#14-do-not-use-openexternal-with-untrusted-content) +15. [Disable the `remote` module](#15-disable-the-remote-module) +16. [Filter the `remote` module](#16-filter-the-remote-module) To automate the detection of misconfigurations and insecure patterns, it is possible to use @@ -709,6 +711,122 @@ const { shell } = require('electron') shell.openExternal('https://example.com/index.html') ``` +## 15) Disable the `remote` module + +The `remote` module provides a way for the renderer processes to +access APIs normally only available in the main process. Using it, a +renderer can invoke methods of a main process object without explicitly sending +inter-process messages. If your desktop application does not run untrusted +content, this can be a useful way to have your renderer processes access and +work with modules that are only available to the main process, such as +GUI-related modules (dialogs, menus, etc.). + +However, if your app can run untrusted content and even if you +[sandbox][sandbox] your renderer processes accordingly, the `remote` module +makes it easy for malicious code to escape the sandbox and have access to +system resources via the higher privileges of the main process. Therefore, +it should be disabled in such circumstances. + +### Why? + +`remote` uses an internal IPC channel to communicate with the main process. +"Prototype pollution" attacks can grant malicious code access to the internal +IPC channel, which can then be used to escape the sandbox by mimicking `remote` +IPC messages and getting access to main process modules running with higher +privileges. + +Additionally, it's possible for preload scripts to accidentally leak modules to a +sandboxed renderer. Leaking `remote` arms malicious code with a multitude +of main process modules with which to perform an attack. + +Disabling the `remote` module eliminates these attack vectors. Enabling +context isolation also prevents the "prototype pollution" attacks from +succeeding. + +### How? + +```js +// Bad if the renderer can run untrusted content +const mainWindow = new BrowserWindow({}) +``` + +```js +// Good +const mainWindow = new BrowserWindow({ + webPreferences: { + enableRemoteModule: false + } +}) +``` + +```html + + + + + +``` + +## 16) Filter the `remote` module + +If you cannot disable the `remote` module, you should filter the globals, +Node, and Electron modules (so-called built-ins) accessible via `remote` +that your application does not require. This can be done by blocking +certain modules entirely and by replacing others with proxies that +expose only the functionality that your app needs. + +### Why? + +Due to the system access privileges of the main process, functionality +provided by the main process modules may be dangerous in the hands of +malicious code running in a compromised renderer process. By limiting +the set of accessible modules to the minimum that your app needs and +filtering out the others, you reduce the toolset that malicious code +can use to attack the system. + +### How? + +```js +const readOnlyFsProxy = require(/* ... */) // exposes only file read functionality + +const allowedModules = new Set(['crypto']) +const proxiedModules = new Map(['fs', readOnlyFsProxy]) +const allowedElectronModules = new Set(['shell']) +const allowedGlobals = new Set() + +app.on('remote-require', (event, webContents, moduleName) => { + if (proxiedModules.has(moduleName)) { + event.returnValue = proxiedModules.get(moduleName) + } + if (!allowedModules.has(moduleName)) { + event.preventDefault() + } +}) + +app.on('remote-get-builtin', (event, webContents, moduleName) => { + if (!allowedElectronModules.has(moduleName)) { + event.preventDefault() + } +}) + +app.on('remote-get-global', (event, webContents, globalName) => { + if (!allowedGlobals.has(globalName)) { + event.preventDefault() + } +}) + +app.on('remote-get-current-window', (event, webContents) => { + event.preventDefault() +}) + +app.on('remote-get-current-web-contents', (event, webContents) => { + event.preventDefault() +}) + +app.on('remote-get-guest-web-contents', (event, webContents, guestWebContents) => { + event.preventDefault() +}) +``` [browser-window]: ../api/browser-window.md [browser-view]: ../api/browser-view.md @@ -717,3 +835,4 @@ shell.openExternal('https://example.com/index.html') [new-window]: ../api/web-contents.md#event-new-window [will-navigate]: ../api/web-contents.md#event-will-navigate [open-external]: ../api/shell.md#shellopenexternalurl-options-callback +[sandbox]: ../api/sandbox-option.md From d7a927fd7a04ba27ad27193df01385616c2fe223 Mon Sep 17 00:00:00 2001 From: Pedro Pontes Date: Thu, 4 Apr 2019 21:26:17 +0200 Subject: [PATCH 2/3] docs: state clearly that disabling remote is safer than filtering. --- docs/tutorial/security.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/tutorial/security.md b/docs/tutorial/security.md index 1f1b5aa597999..8606a0a039eeb 100644 --- a/docs/tutorial/security.md +++ b/docs/tutorial/security.md @@ -782,7 +782,10 @@ provided by the main process modules may be dangerous in the hands of malicious code running in a compromised renderer process. By limiting the set of accessible modules to the minimum that your app needs and filtering out the others, you reduce the toolset that malicious code -can use to attack the system. +can use to attack the system. Note that you'll still be vulnerable to +"prototype pollution" attacks on the remote module internal mechanism, +so [disabling it fully](#15-disable-the-remote-module) is always the +safest option. ### How? From ffb9c870d5cdcc39fb0e2ea7de321660ba3bf43f Mon Sep 17 00:00:00 2001 From: Pedro Pontes Date: Thu, 4 Apr 2019 22:11:47 +0200 Subject: [PATCH 3/3] docs: clearer wording when advising to disable remote module. --- docs/tutorial/security.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/tutorial/security.md b/docs/tutorial/security.md index 8606a0a039eeb..e71fbdd139da1 100644 --- a/docs/tutorial/security.md +++ b/docs/tutorial/security.md @@ -782,10 +782,13 @@ provided by the main process modules may be dangerous in the hands of malicious code running in a compromised renderer process. By limiting the set of accessible modules to the minimum that your app needs and filtering out the others, you reduce the toolset that malicious code -can use to attack the system. Note that you'll still be vulnerable to -"prototype pollution" attacks on the remote module internal mechanism, -so [disabling it fully](#15-disable-the-remote-module) is always the -safest option. +can use to attack the system. + +Note that the safest option is to +[fully disable the remote module](#15-disable-the-remote-module). If +you choose to filter access rather than completely disable the module, +you must be very careful to ensure that no escalation of privilege is +possible through the modules you allow past the filter. ### How?