2022-02-16 17:47:32 +00:00
|
|
|
|
---
|
|
|
|
|
title: Security
|
|
|
|
|
description: A set of guidelines for building secure Electron apps
|
|
|
|
|
slug: security
|
|
|
|
|
hide_title: true
|
|
|
|
|
toc_max_heading_level: 3
|
|
|
|
|
---
|
|
|
|
|
# Security
|
|
|
|
|
|
|
|
|
|
:::info Reporting security issues
|
|
|
|
|
For information on how to properly disclose an Electron vulnerability,
|
2023-04-16 04:20:59 +00:00
|
|
|
|
see [SECURITY.md](https://github.com/electron/electron/blob/main/SECURITY.md).
|
2022-02-16 17:47:32 +00:00
|
|
|
|
|
|
|
|
|
For upstream Chromium vulnerabilities: Electron keeps up to date with alternating
|
|
|
|
|
Chromium releases. For more information, see the
|
|
|
|
|
[Electron Release Timelines](../tutorial/electron-timelines.md) document.
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
|
|
## Preface
|
2016-05-06 10:23:18 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
As web developers, we usually enjoy the strong security net of the browser —
|
2018-01-29 19:19:43 +00:00
|
|
|
|
the risks associated with the code we write are relatively small. Our websites
|
|
|
|
|
are granted limited powers in a sandbox, and we trust that our users enjoy a
|
|
|
|
|
browser built by a large team of engineers that is able to quickly respond to
|
|
|
|
|
newly discovered security threats.
|
2016-05-06 10:23:18 +00:00
|
|
|
|
|
2016-05-08 18:21:11 +00:00
|
|
|
|
When working with Electron, it is important to understand that Electron is not
|
|
|
|
|
a web browser. It allows you to build feature-rich desktop applications with
|
|
|
|
|
familiar web technologies, but your code wields much greater power. JavaScript
|
2016-06-01 05:36:45 +00:00
|
|
|
|
can access the filesystem, user shell, and more. This allows you to build
|
2018-01-29 19:19:43 +00:00
|
|
|
|
high quality native applications, but the inherent security risks scale with
|
|
|
|
|
the additional powers granted to your code.
|
2016-05-06 10:23:18 +00:00
|
|
|
|
|
2018-01-30 00:01:05 +00:00
|
|
|
|
With that in mind, be aware that displaying arbitrary content from untrusted
|
2016-05-08 18:21:11 +00:00
|
|
|
|
sources poses a severe security risk that Electron is not intended to handle.
|
2016-05-10 08:41:16 +00:00
|
|
|
|
In fact, the most popular Electron apps (Atom, Slack, Visual Studio Code, etc)
|
|
|
|
|
display primarily local content (or trusted, secure remote content without Node
|
2022-02-16 17:47:32 +00:00
|
|
|
|
integration) — if your application executes code from an online source, it is
|
2016-05-10 08:41:16 +00:00
|
|
|
|
your responsibility to ensure that the code is not malicious.
|
2016-05-06 10:23:18 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
## General guidelines
|
2016-05-06 10:23:18 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
### Security is everyone's responsibility
|
2016-09-08 17:39:29 +00:00
|
|
|
|
|
2019-02-27 18:09:38 +00:00
|
|
|
|
It is important to remember that the security of your Electron application is
|
|
|
|
|
the result of the overall security of the framework foundation
|
2023-04-03 11:20:10 +00:00
|
|
|
|
(_Chromium_, _Node.js_), Electron itself, all NPM dependencies and
|
2019-02-27 18:09:38 +00:00
|
|
|
|
your code. As such, it is your responsibility to follow a few important best
|
|
|
|
|
practices:
|
|
|
|
|
|
2019-03-20 20:12:47 +00:00
|
|
|
|
* **Keep your application up-to-date with the latest Electron framework release.**
|
|
|
|
|
When releasing your product, you’re also shipping a bundle composed of Electron,
|
|
|
|
|
Chromium shared library and Node.js. Vulnerabilities affecting these components
|
|
|
|
|
may impact the security of your application. By updating Electron to the latest
|
2023-04-03 11:20:10 +00:00
|
|
|
|
version, you ensure that critical vulnerabilities (such as _nodeIntegration bypasses_)
|
2019-09-14 01:12:14 +00:00
|
|
|
|
are already patched and cannot be exploited in your application. For more information,
|
2021-07-19 19:45:47 +00:00
|
|
|
|
see "[Use a current version of Electron](#16-use-a-current-version-of-electron)".
|
2019-02-27 18:09:38 +00:00
|
|
|
|
|
2019-03-20 20:12:47 +00:00
|
|
|
|
* **Evaluate your dependencies.** While NPM provides half a million reusable packages,
|
|
|
|
|
it is your responsibility to choose trusted 3rd-party libraries. If you use outdated
|
|
|
|
|
libraries affected by known vulnerabilities or rely on poorly maintained code,
|
2019-02-27 18:09:38 +00:00
|
|
|
|
your application security could be in jeopardy.
|
|
|
|
|
|
2019-03-20 20:12:47 +00:00
|
|
|
|
* **Adopt secure coding practices.** The first line of defense for your application
|
|
|
|
|
is your own code. Common web vulnerabilities, such as Cross-Site Scripting (XSS),
|
|
|
|
|
have a higher security impact on Electron applications hence it is highly recommended
|
2019-02-27 18:09:38 +00:00
|
|
|
|
to adopt secure software development best practices and perform security testing.
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
### Isolation for untrusted content
|
2019-02-27 18:09:38 +00:00
|
|
|
|
|
|
|
|
|
A security issue exists whenever you receive code from an untrusted source (e.g.
|
|
|
|
|
a remote server) and execute it locally. As an example, consider a remote
|
|
|
|
|
website being displayed inside a default [`BrowserWindow`][browser-window]. If
|
|
|
|
|
an attacker somehow manages to change said content (either by attacking the
|
|
|
|
|
source directly, or by sitting between your app and the actual destination), they
|
|
|
|
|
will be able to execute native code on the user's machine.
|
2016-05-06 10:23:18 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
:::warning
|
|
|
|
|
Under no circumstances should you load and execute remote code with
|
2018-01-29 19:19:43 +00:00
|
|
|
|
Node.js integration enabled. Instead, use only local files (packaged together
|
|
|
|
|
with your application) to execute Node.js code. To display remote content, use
|
2023-12-13 21:01:03 +00:00
|
|
|
|
the [`<webview>`][webview-tag] tag or a [`WebContentsView`][web-contents-view]
|
|
|
|
|
and make sure to disable the `nodeIntegration` and enable `contextIsolation`.
|
2022-02-16 17:47:32 +00:00
|
|
|
|
:::
|
2016-05-06 10:23:18 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
:::info Electron security warnings
|
|
|
|
|
Security warnings and recommendations are printed to the developer console.
|
|
|
|
|
They only show up when the binary's name is Electron, indicating that a developer
|
|
|
|
|
is currently looking at the console.
|
2018-02-03 14:50:12 +00:00
|
|
|
|
|
|
|
|
|
You can force-enable or force-disable these warnings by setting
|
|
|
|
|
`ELECTRON_ENABLE_SECURITY_WARNINGS` or `ELECTRON_DISABLE_SECURITY_WARNINGS` on
|
|
|
|
|
either `process.env` or the `window` object.
|
2022-02-16 17:47:32 +00:00
|
|
|
|
:::
|
2018-02-03 14:50:12 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
## Checklist: Security recommendations
|
2018-02-03 14:50:12 +00:00
|
|
|
|
|
2019-02-27 18:09:38 +00:00
|
|
|
|
You should at least follow these steps to improve the security of your application:
|
2016-05-06 10:23:18 +00:00
|
|
|
|
|
2018-05-02 15:33:07 +00:00
|
|
|
|
1. [Only load secure content](#1-only-load-secure-content)
|
2019-04-29 21:29:27 +00:00
|
|
|
|
2. [Disable the Node.js integration in all renderers that display remote content](#2-do-not-enable-nodejs-integration-for-remote-content)
|
2022-04-18 14:09:54 +00:00
|
|
|
|
3. [Enable context isolation in all renderers](#3-enable-context-isolation)
|
2022-02-16 17:47:32 +00:00
|
|
|
|
4. [Enable process sandboxing](#4-enable-process-sandboxing)
|
2021-07-19 19:45:47 +00:00
|
|
|
|
5. [Use `ses.setPermissionRequestHandler()` in all sessions that load remote content](#5-handle-session-permission-requests-from-remote-content)
|
|
|
|
|
6. [Do not disable `webSecurity`](#6-do-not-disable-websecurity)
|
|
|
|
|
7. [Define a `Content-Security-Policy`](#7-define-a-content-security-policy) and use restrictive rules (i.e. `script-src 'self'`)
|
2022-02-16 17:47:32 +00:00
|
|
|
|
8. [Do not enable `allowRunningInsecureContent`](#8-do-not-enable-allowrunninginsecurecontent)
|
2021-07-19 19:45:47 +00:00
|
|
|
|
9. [Do not enable experimental features](#9-do-not-enable-experimental-features)
|
|
|
|
|
10. [Do not use `enableBlinkFeatures`](#10-do-not-use-enableblinkfeatures)
|
2022-02-16 17:47:32 +00:00
|
|
|
|
11. [`<webview>`: Do not use `allowpopups`](#11-do-not-use-allowpopups-for-webviews)
|
2021-07-19 19:45:47 +00:00
|
|
|
|
12. [`<webview>`: Verify options and params](#12-verify-webview-options-before-creation)
|
|
|
|
|
13. [Disable or limit navigation](#13-disable-or-limit-navigation)
|
|
|
|
|
14. [Disable or limit creation of new windows](#14-disable-or-limit-creation-of-new-windows)
|
2022-02-16 17:47:32 +00:00
|
|
|
|
15. [Do not use `shell.openExternal` with untrusted content](#15-do-not-use-shellopenexternal-with-untrusted-content)
|
2021-07-19 19:45:47 +00:00
|
|
|
|
16. [Use a current version of Electron](#16-use-a-current-version-of-electron)
|
2022-09-13 20:56:41 +00:00
|
|
|
|
17. [Validate the `sender` of all IPC messages](#17-validate-the-sender-of-all-ipc-messages)
|
2019-02-27 18:09:38 +00:00
|
|
|
|
|
|
|
|
|
To automate the detection of misconfigurations and insecure patterns, it is
|
|
|
|
|
possible to use
|
2022-02-16 17:47:32 +00:00
|
|
|
|
[Electronegativity](https://github.com/doyensec/electronegativity). For
|
2019-02-27 18:09:38 +00:00
|
|
|
|
additional details on potential weaknesses and implementation bugs when
|
|
|
|
|
developing applications using Electron, please refer to this [guide for
|
2022-02-16 17:47:32 +00:00
|
|
|
|
developers and auditors](https://doyensec.com/resources/us-17-Carettoni-Electronegativity-A-Study-Of-Electron-Security-wp.pdf).
|
2018-01-29 19:19:43 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
### 1. Only load secure content
|
2018-01-29 19:19:43 +00:00
|
|
|
|
|
|
|
|
|
Any resources not included with your application should be loaded using a
|
2018-01-29 20:34:46 +00:00
|
|
|
|
secure protocol like `HTTPS`. In other words, do not use insecure protocols
|
2018-02-13 05:18:27 +00:00
|
|
|
|
like `HTTP`. Similarly, we recommend the use of `WSS` over `WS`, `FTPS` over
|
2018-01-30 00:01:05 +00:00
|
|
|
|
`FTP`, and so on.
|
2018-01-29 00:55:11 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### Why?
|
2018-01-29 19:19:43 +00:00
|
|
|
|
|
2022-09-21 20:19:04 +00:00
|
|
|
|
`HTTPS` has two main benefits:
|
2018-01-29 00:55:11 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
1. It ensures data integrity, asserting that the data was not modified while in
|
2018-01-29 01:25:05 +00:00
|
|
|
|
transit between your application and the host.
|
2022-02-16 17:47:32 +00:00
|
|
|
|
1. It encrypts the traffic between your user and the destination host, making it
|
2018-01-30 00:01:05 +00:00
|
|
|
|
more difficult to eavesdrop on the information sent between your app and
|
2018-01-29 01:25:05 +00:00
|
|
|
|
the host.
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### How?
|
2018-01-29 19:19:43 +00:00
|
|
|
|
|
2023-06-05 07:26:26 +00:00
|
|
|
|
```js title='main.js (Main Process)' @ts-type={browserWindow:Electron.BrowserWindow}
|
2018-01-29 00:55:11 +00:00
|
|
|
|
// Bad
|
2019-02-27 18:09:38 +00:00
|
|
|
|
browserWindow.loadURL('http://example.com')
|
2018-01-29 00:55:11 +00:00
|
|
|
|
|
|
|
|
|
// Good
|
2019-02-27 18:09:38 +00:00
|
|
|
|
browserWindow.loadURL('https://example.com')
|
2018-01-29 00:55:11 +00:00
|
|
|
|
```
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
```html title='index.html (Renderer Process)'
|
2018-01-29 00:55:11 +00:00
|
|
|
|
<!-- Bad -->
|
2019-02-27 18:09:38 +00:00
|
|
|
|
<script crossorigin src="http://example.com/react.js"></script>
|
|
|
|
|
<link rel="stylesheet" href="http://example.com/style.css">
|
2018-01-29 00:55:11 +00:00
|
|
|
|
|
|
|
|
|
<!-- Good -->
|
2019-02-27 18:09:38 +00:00
|
|
|
|
<script crossorigin src="https://example.com/react.js"></script>
|
|
|
|
|
<link rel="stylesheet" href="https://example.com/style.css">
|
2018-01-29 00:55:11 +00:00
|
|
|
|
```
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
### 2. Do not enable Node.js integration for remote content
|
2018-01-29 01:25:05 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
:::info
|
|
|
|
|
This recommendation is the default behavior in Electron since 5.0.0.
|
|
|
|
|
:::
|
2019-04-29 21:29:27 +00:00
|
|
|
|
|
|
|
|
|
It is paramount that you do not enable Node.js integration in any renderer
|
2023-12-13 21:01:03 +00:00
|
|
|
|
([`BrowserWindow`][browser-window], [`WebContentsView`][web-contents-view], or
|
2018-06-21 14:39:07 +00:00
|
|
|
|
[`<webview>`][webview-tag]) that loads remote content. The goal is to limit the
|
2018-01-30 00:01:05 +00:00
|
|
|
|
powers you grant to remote content, thus making it dramatically more difficult
|
|
|
|
|
for an attacker to harm your users should they gain the ability to execute
|
|
|
|
|
JavaScript on your website.
|
2018-01-29 19:19:43 +00:00
|
|
|
|
|
2018-01-30 00:01:05 +00:00
|
|
|
|
After this, you can grant additional permissions for specific hosts. For example,
|
2019-10-07 16:26:38 +00:00
|
|
|
|
if you are opening a BrowserWindow pointed at `https://example.com/`, you can
|
2018-01-30 00:01:05 +00:00
|
|
|
|
give that website exactly the abilities it needs, but no more.
|
2018-01-29 01:25:05 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### Why?
|
2018-01-29 19:19:43 +00:00
|
|
|
|
|
2018-01-30 00:01:05 +00:00
|
|
|
|
A cross-site-scripting (XSS) attack is more dangerous if an attacker can jump
|
|
|
|
|
out of the renderer process and execute code on the user's computer.
|
|
|
|
|
Cross-site-scripting attacks are fairly common - and while an issue, their
|
|
|
|
|
power is usually limited to messing with the website that they are executed on.
|
|
|
|
|
Disabling Node.js integration helps prevent an XSS from being escalated into a
|
|
|
|
|
so-called "Remote Code Execution" (RCE) attack.
|
2018-01-29 01:25:05 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### How?
|
2018-01-29 19:19:43 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
```js title='main.js (Main Process)'
|
2018-01-29 01:25:05 +00:00
|
|
|
|
// Bad
|
2019-04-29 21:29:27 +00:00
|
|
|
|
const mainWindow = new BrowserWindow({
|
|
|
|
|
webPreferences: {
|
2022-02-16 17:47:32 +00:00
|
|
|
|
contextIsolation: false,
|
2019-04-29 21:29:27 +00:00
|
|
|
|
nodeIntegration: true,
|
|
|
|
|
nodeIntegrationInWorker: true
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
2019-02-27 18:09:38 +00:00
|
|
|
|
mainWindow.loadURL('https://example.com')
|
2018-01-29 20:36:51 +00:00
|
|
|
|
```
|
2018-01-29 01:25:05 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
```js title='main.js (Main Process)'
|
2018-01-29 01:25:05 +00:00
|
|
|
|
// Good
|
|
|
|
|
const mainWindow = new BrowserWindow({
|
|
|
|
|
webPreferences: {
|
2019-03-28 10:38:51 +00:00
|
|
|
|
preload: path.join(app.getAppPath(), 'preload.js')
|
2018-01-29 01:25:05 +00:00
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
2019-02-27 18:09:38 +00:00
|
|
|
|
mainWindow.loadURL('https://example.com')
|
2018-01-29 01:25:05 +00:00
|
|
|
|
```
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
```html title='index.html (Renderer Process)'
|
2018-01-29 19:19:43 +00:00
|
|
|
|
<!-- Bad -->
|
|
|
|
|
<webview nodeIntegration src="page.html"></webview>
|
2018-01-29 01:25:05 +00:00
|
|
|
|
|
2018-01-29 19:19:43 +00:00
|
|
|
|
<!-- Good -->
|
|
|
|
|
<webview src="page.html"></webview>
|
|
|
|
|
```
|
|
|
|
|
|
2018-01-30 00:01:05 +00:00
|
|
|
|
When disabling Node.js integration, you can still expose APIs to your website that
|
2018-01-29 19:19:43 +00:00
|
|
|
|
do consume Node.js modules or features. Preload scripts continue to have access
|
|
|
|
|
to `require` and other Node.js features, allowing developers to expose a custom
|
2022-02-16 17:47:32 +00:00
|
|
|
|
API to remotely loaded content via the [contextBridge API](../api/context-bridge.md).
|
2018-01-29 01:25:05 +00:00
|
|
|
|
|
2022-04-18 14:09:54 +00:00
|
|
|
|
### 3. Enable Context Isolation
|
2018-01-29 01:25:05 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
:::info
|
|
|
|
|
This recommendation is the default behavior in Electron since 12.0.0.
|
|
|
|
|
:::
|
2018-01-29 19:01:22 +00:00
|
|
|
|
|
2018-01-29 19:19:21 +00:00
|
|
|
|
Context isolation is an Electron feature that allows developers to run code
|
|
|
|
|
in preload scripts and in Electron APIs in a dedicated JavaScript context. In
|
|
|
|
|
practice, that means that global objects like `Array.prototype.push` or
|
|
|
|
|
`JSON.parse` cannot be modified by scripts running in the renderer process.
|
|
|
|
|
|
|
|
|
|
Electron uses the same technology as Chromium's [Content Scripts](https://developer.chrome.com/extensions/content_scripts#execution-environment)
|
|
|
|
|
to enable this behavior.
|
|
|
|
|
|
2020-11-18 06:24:00 +00:00
|
|
|
|
Even when `nodeIntegration: false` is used, to truly enforce strong isolation
|
|
|
|
|
and prevent the use of Node primitives `contextIsolation` **must** also be used.
|
2019-02-27 18:09:38 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
:::info
|
2020-05-11 20:01:32 +00:00
|
|
|
|
For more information on what `contextIsolation` is and how to enable it please
|
|
|
|
|
see our dedicated [Context Isolation](context-isolation.md) document.
|
2022-02-16 17:47:32 +00:00
|
|
|
|
:::info
|
2018-01-29 19:19:21 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
### 4. Enable process sandboxing
|
2021-07-19 19:45:47 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
[Sandboxing](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/design/sandbox.md)
|
|
|
|
|
is a Chromium feature that uses the operating system to
|
2021-07-19 19:45:47 +00:00
|
|
|
|
significantly limit what renderer processes have access to. You should enable
|
|
|
|
|
the sandbox in all renderers. Loading, reading or processing any untrusted
|
|
|
|
|
content in an unsandboxed process, including the main process, is not advised.
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
:::info
|
2022-09-20 15:14:44 +00:00
|
|
|
|
For more information on what Process Sandboxing is and how to enable it please
|
2022-02-16 17:47:32 +00:00
|
|
|
|
see our dedicated [Process Sandboxing](sandbox.md) document.
|
|
|
|
|
:::info
|
2021-07-19 19:45:47 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
### 5. Handle session permission requests from remote content
|
2018-01-29 19:01:22 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
You may have seen permission requests while using Chrome: they pop up whenever
|
2018-01-29 19:01:22 +00:00
|
|
|
|
the website attempts to use a feature that the user has to manually approve (
|
|
|
|
|
like notifications).
|
|
|
|
|
|
|
|
|
|
The API is based on the [Chromium permissions API](https://developer.chrome.com/extensions/permissions)
|
|
|
|
|
and implements the same types of permissions.
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### Why?
|
2018-01-29 19:01:22 +00:00
|
|
|
|
|
|
|
|
|
By default, Electron will automatically approve all permission requests unless
|
|
|
|
|
the developer has manually configured a custom handler. While a solid default,
|
|
|
|
|
security-conscious developers might want to assume the very opposite.
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### How?
|
2018-01-29 19:01:22 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
```js title='main.js (Main Process)'
|
2018-01-29 19:01:22 +00:00
|
|
|
|
const { session } = require('electron')
|
2023-06-05 07:26:26 +00:00
|
|
|
|
const { URL } = require('url')
|
2018-01-29 19:01:22 +00:00
|
|
|
|
|
|
|
|
|
session
|
|
|
|
|
.fromPartition('some-partition')
|
|
|
|
|
.setPermissionRequestHandler((webContents, permission, callback) => {
|
2022-03-28 18:25:44 +00:00
|
|
|
|
const parsedUrl = new URL(webContents.getURL())
|
2018-01-29 19:01:22 +00:00
|
|
|
|
|
|
|
|
|
if (permission === 'notifications') {
|
|
|
|
|
// Approves the permissions request
|
|
|
|
|
callback(true)
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-06 18:43:58 +00:00
|
|
|
|
// Verify URL
|
2022-03-28 18:25:44 +00:00
|
|
|
|
if (parsedUrl.protocol !== 'https:' || parsedUrl.host !== 'example.com') {
|
2018-01-29 19:01:22 +00:00
|
|
|
|
// Denies the permissions request
|
|
|
|
|
return callback(false)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
### 6. Do not disable `webSecurity`
|
2018-02-01 17:58:02 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
:::info
|
|
|
|
|
This recommendation is Electron's default.
|
|
|
|
|
:::
|
2018-02-01 17:58:02 +00:00
|
|
|
|
|
|
|
|
|
You may have already guessed that disabling the `webSecurity` property on a
|
|
|
|
|
renderer process ([`BrowserWindow`][browser-window],
|
2023-12-13 21:01:03 +00:00
|
|
|
|
[`WebContentsView`][web-contents-view], or [`<webview>`][webview-tag]) disables
|
|
|
|
|
crucial security features.
|
2018-02-01 17:58:02 +00:00
|
|
|
|
|
|
|
|
|
Do not disable `webSecurity` in production applications.
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### Why?
|
2018-02-01 17:58:02 +00:00
|
|
|
|
|
|
|
|
|
Disabling `webSecurity` will disable the same-origin policy and set
|
|
|
|
|
`allowRunningInsecureContent` property to `true`. In other words, it allows
|
|
|
|
|
the execution of insecure code from different domains.
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### How?
|
2020-11-05 22:12:43 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
```js title='main.js (Main Process)'
|
2018-02-01 17:58:02 +00:00
|
|
|
|
// Bad
|
|
|
|
|
const mainWindow = new BrowserWindow({
|
|
|
|
|
webPreferences: {
|
|
|
|
|
webSecurity: false
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
```js title='main.js (Main Process)'
|
2018-02-01 17:58:02 +00:00
|
|
|
|
// Good
|
|
|
|
|
const mainWindow = new BrowserWindow()
|
|
|
|
|
```
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
```html title='index.html (Renderer Process)'
|
2018-02-01 17:58:02 +00:00
|
|
|
|
<!-- Bad -->
|
|
|
|
|
<webview disablewebsecurity src="page.html"></webview>
|
|
|
|
|
|
|
|
|
|
<!-- Good -->
|
|
|
|
|
<webview src="page.html"></webview>
|
|
|
|
|
```
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
### 7. Define a Content Security Policy
|
2018-01-29 19:02:30 +00:00
|
|
|
|
|
|
|
|
|
A Content Security Policy (CSP) is an additional layer of protection against
|
2018-01-30 00:01:05 +00:00
|
|
|
|
cross-site-scripting attacks and data injection attacks. We recommend that they
|
|
|
|
|
be enabled by any website you load inside Electron.
|
2018-01-29 19:02:30 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### Why?
|
2018-01-29 19:02:30 +00:00
|
|
|
|
|
|
|
|
|
CSP allows the server serving content to restrict and control the resources
|
2019-02-27 18:09:38 +00:00
|
|
|
|
Electron can load for that given web page. `https://example.com` should
|
2018-01-30 00:01:05 +00:00
|
|
|
|
be allowed to load scripts from the origins you defined while scripts from
|
2018-01-29 19:02:30 +00:00
|
|
|
|
`https://evil.attacker.com` should not be allowed to run. Defining a CSP is an
|
2018-06-20 00:36:37 +00:00
|
|
|
|
easy way to improve your application's security.
|
2018-01-29 19:02:30 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### How?
|
|
|
|
|
|
2018-01-29 19:02:30 +00:00
|
|
|
|
The following CSP will allow Electron to execute scripts from the current
|
2019-02-27 18:09:38 +00:00
|
|
|
|
website and from `apis.example.com`.
|
2018-01-29 19:02:30 +00:00
|
|
|
|
|
2019-07-30 20:11:56 +00:00
|
|
|
|
```plaintext
|
2018-01-29 19:02:30 +00:00
|
|
|
|
// Bad
|
|
|
|
|
Content-Security-Policy: '*'
|
|
|
|
|
|
|
|
|
|
// Good
|
2019-02-27 18:09:38 +00:00
|
|
|
|
Content-Security-Policy: script-src 'self' https://apis.example.com
|
2018-01-29 19:02:30 +00:00
|
|
|
|
```
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### CSP HTTP headers
|
2018-06-20 00:36:37 +00:00
|
|
|
|
|
|
|
|
|
Electron respects the [`Content-Security-Policy` HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy)
|
2018-07-16 20:32:42 +00:00
|
|
|
|
which can be set using Electron's
|
2018-06-20 00:36:37 +00:00
|
|
|
|
[`webRequest.onHeadersReceived`](../api/web-request.md#webrequestonheadersreceivedfilter-listener)
|
|
|
|
|
handler:
|
|
|
|
|
|
2023-11-21 07:50:08 +00:00
|
|
|
|
```js title='main.js (Main Process)'
|
2018-09-13 16:10:51 +00:00
|
|
|
|
const { session } = require('electron')
|
2018-06-20 00:36:37 +00:00
|
|
|
|
|
|
|
|
|
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
|
2018-10-23 14:38:48 +00:00
|
|
|
|
callback({
|
|
|
|
|
responseHeaders: {
|
|
|
|
|
...details.responseHeaders,
|
|
|
|
|
'Content-Security-Policy': ['default-src \'none\'']
|
|
|
|
|
}
|
|
|
|
|
})
|
2018-06-20 00:36:37 +00:00
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### CSP meta tag
|
2018-06-20 00:36:37 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
CSP's preferred delivery mechanism is an HTTP header. However, it is not possible
|
2018-11-28 08:58:18 +00:00
|
|
|
|
to use this method when loading a resource using the `file://` protocol. It can
|
2022-02-16 17:47:32 +00:00
|
|
|
|
be useful in some cases to set a policy on a page directly in the markup using a
|
|
|
|
|
`<meta>` tag:
|
2018-06-20 00:36:37 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
```html title='index.html (Renderer Process)'
|
2018-06-20 00:36:37 +00:00
|
|
|
|
<meta http-equiv="Content-Security-Policy" content="default-src 'none'">
|
|
|
|
|
```
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
### 8. Do not enable `allowRunningInsecureContent`
|
2018-01-29 19:03:06 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
:::info
|
|
|
|
|
This recommendation is Electron's default.
|
|
|
|
|
:::
|
2018-01-29 20:34:46 +00:00
|
|
|
|
|
2018-03-27 23:15:29 +00:00
|
|
|
|
By default, Electron will not allow websites loaded over `HTTPS` to load and
|
2018-01-29 19:03:06 +00:00
|
|
|
|
execute scripts, CSS, or plugins from insecure sources (`HTTP`). Setting the
|
|
|
|
|
property `allowRunningInsecureContent` to `true` disables that protection.
|
|
|
|
|
|
|
|
|
|
Loading the initial HTML of a website over `HTTPS` and attempting to load
|
|
|
|
|
subsequent resources via `HTTP` is also known as "mixed content".
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### Why?
|
2018-01-29 19:03:06 +00:00
|
|
|
|
|
2018-05-08 05:16:09 +00:00
|
|
|
|
Loading content over `HTTPS` assures the authenticity and integrity
|
2018-01-30 00:01:05 +00:00
|
|
|
|
of the loaded resources while encrypting the traffic itself. See the section on
|
2018-05-02 15:33:07 +00:00
|
|
|
|
[only displaying secure content](#1-only-load-secure-content) for more details.
|
2018-01-29 19:03:06 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### How?
|
2018-01-29 19:03:06 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
```js title='main.js (Main Process)'
|
2018-01-29 19:03:06 +00:00
|
|
|
|
// Bad
|
|
|
|
|
const mainWindow = new BrowserWindow({
|
|
|
|
|
webPreferences: {
|
|
|
|
|
allowRunningInsecureContent: true
|
|
|
|
|
}
|
|
|
|
|
})
|
2018-01-29 20:36:51 +00:00
|
|
|
|
```
|
2018-01-29 19:03:06 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
```js title='main.js (Main Process)'
|
2018-01-29 19:03:06 +00:00
|
|
|
|
// Good
|
|
|
|
|
const mainWindow = new BrowserWindow({})
|
|
|
|
|
```
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
### 9. Do not enable experimental features
|
2018-01-29 19:03:27 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
:::info
|
|
|
|
|
This recommendation is Electron's default.
|
|
|
|
|
:::
|
2018-01-29 20:34:46 +00:00
|
|
|
|
|
2018-01-29 19:03:27 +00:00
|
|
|
|
Advanced users of Electron can enable experimental Chromium features using the
|
2018-07-16 20:32:42 +00:00
|
|
|
|
`experimentalFeatures` property.
|
2018-01-29 19:03:27 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### Why?
|
2018-01-29 19:03:27 +00:00
|
|
|
|
|
|
|
|
|
Experimental features are, as the name suggests, experimental and have not been
|
2018-02-13 05:18:27 +00:00
|
|
|
|
enabled for all Chromium users. Furthermore, their impact on Electron as a whole
|
2018-01-29 19:03:27 +00:00
|
|
|
|
has likely not been tested.
|
|
|
|
|
|
|
|
|
|
Legitimate use cases exist, but unless you know what you are doing, you should
|
|
|
|
|
not enable this property.
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### How?
|
2018-01-29 19:03:27 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
```js title='main.js (Main Process)'
|
2018-01-29 19:03:27 +00:00
|
|
|
|
// Bad
|
|
|
|
|
const mainWindow = new BrowserWindow({
|
|
|
|
|
webPreferences: {
|
|
|
|
|
experimentalFeatures: true
|
|
|
|
|
}
|
|
|
|
|
})
|
2018-01-29 20:36:51 +00:00
|
|
|
|
```
|
2018-01-29 19:03:27 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
```js title='main.js (Main Process)'
|
2018-01-29 19:03:27 +00:00
|
|
|
|
// Good
|
|
|
|
|
const mainWindow = new BrowserWindow({})
|
|
|
|
|
```
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
### 10. Do not use `enableBlinkFeatures`
|
2018-01-29 20:34:46 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
:::info
|
|
|
|
|
This recommendation is Electron's default.
|
|
|
|
|
:::
|
2018-01-29 20:34:46 +00:00
|
|
|
|
|
2018-01-30 00:01:05 +00:00
|
|
|
|
Blink is the name of the rendering engine behind Chromium. As with
|
2018-05-23 21:01:34 +00:00
|
|
|
|
`experimentalFeatures`, the `enableBlinkFeatures` property allows developers to
|
2018-01-29 19:03:38 +00:00
|
|
|
|
enable features that have been disabled by default.
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### Why?
|
2018-01-29 19:03:38 +00:00
|
|
|
|
|
|
|
|
|
Generally speaking, there are likely good reasons if a feature was not enabled
|
|
|
|
|
by default. Legitimate use cases for enabling specific features exist. As a
|
|
|
|
|
developer, you should know exactly why you need to enable a feature, what the
|
|
|
|
|
ramifications are, and how it impacts the security of your application. Under
|
|
|
|
|
no circumstances should you enable features speculatively.
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### How?
|
2020-11-05 22:12:43 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
```js title='main.js (Main Process)'
|
2018-01-29 19:03:38 +00:00
|
|
|
|
// Bad
|
|
|
|
|
const mainWindow = new BrowserWindow({
|
|
|
|
|
webPreferences: {
|
2019-09-03 07:02:22 +00:00
|
|
|
|
enableBlinkFeatures: 'ExecCommandInJavaScript'
|
2018-01-29 19:03:38 +00:00
|
|
|
|
}
|
|
|
|
|
})
|
2018-01-29 20:36:51 +00:00
|
|
|
|
```
|
2018-01-29 19:03:38 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
```js title='main.js (Main Process)'
|
2018-01-29 19:03:38 +00:00
|
|
|
|
// Good
|
|
|
|
|
const mainWindow = new BrowserWindow()
|
|
|
|
|
```
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
### 11. Do not use `allowpopups` for WebViews
|
2018-01-29 19:04:02 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
:::info
|
|
|
|
|
This recommendation is Electron's default.
|
|
|
|
|
:::
|
2018-01-29 20:34:46 +00:00
|
|
|
|
|
2018-06-21 14:39:07 +00:00
|
|
|
|
If you are using [`<webview>`][webview-tag], you might need the pages and scripts
|
2018-01-29 20:34:46 +00:00
|
|
|
|
loaded in your `<webview>` tag to open new windows. The `allowpopups` attribute
|
2018-02-20 00:25:02 +00:00
|
|
|
|
enables them to create new [`BrowserWindows`][browser-window] using the
|
2018-06-21 14:39:07 +00:00
|
|
|
|
`window.open()` method. `<webview>` tags are otherwise not allowed to create new
|
2018-01-29 20:34:46 +00:00
|
|
|
|
windows.
|
2018-01-29 19:04:02 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### Why?
|
2018-01-29 19:04:02 +00:00
|
|
|
|
|
|
|
|
|
If you do not need popups, you are better off not allowing the creation of
|
2018-02-20 00:25:02 +00:00
|
|
|
|
new [`BrowserWindows`][browser-window] by default. This follows the principle
|
2018-01-30 00:01:05 +00:00
|
|
|
|
of minimally required access: Don't let a website create new popups unless
|
|
|
|
|
you know it needs that feature.
|
2018-01-29 19:04:02 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### How?
|
2018-01-29 19:04:02 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
```html title='index.html (Renderer Process)'
|
2018-01-29 19:04:02 +00:00
|
|
|
|
<!-- Bad -->
|
|
|
|
|
<webview allowpopups src="page.html"></webview>
|
|
|
|
|
|
|
|
|
|
<!-- Good -->
|
|
|
|
|
<webview src="page.html"></webview>
|
|
|
|
|
```
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
### 12. Verify WebView options before creation
|
2018-01-29 19:19:43 +00:00
|
|
|
|
|
2018-01-29 02:19:49 +00:00
|
|
|
|
A WebView created in a renderer process that does not have Node.js integration
|
|
|
|
|
enabled will not be able to enable integration itself. However, a WebView will
|
|
|
|
|
always create an independent renderer process with its own `webPreferences`.
|
|
|
|
|
|
2018-06-21 14:39:07 +00:00
|
|
|
|
It is a good idea to control the creation of new [`<webview>`][webview-tag] tags
|
|
|
|
|
from the main process and to verify that their webPreferences do not disable
|
2018-01-29 20:34:46 +00:00
|
|
|
|
security features.
|
2018-01-29 02:19:49 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### Why?
|
2018-01-29 19:19:43 +00:00
|
|
|
|
|
2018-06-21 14:39:07 +00:00
|
|
|
|
Since `<webview>` live in the DOM, they can be created by a script running on your
|
2018-01-30 00:01:05 +00:00
|
|
|
|
website even if Node.js integration is otherwise disabled.
|
2018-01-29 02:19:49 +00:00
|
|
|
|
|
|
|
|
|
Electron enables developers to disable various security features that control
|
2018-01-29 19:19:43 +00:00
|
|
|
|
a renderer process. In most cases, developers do not need to disable any of
|
|
|
|
|
those features - and you should therefore not allow different configurations
|
2018-06-21 14:39:07 +00:00
|
|
|
|
for newly created [`<webview>`][webview-tag] tags.
|
2018-01-29 02:19:49 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### How?
|
2018-01-29 19:19:43 +00:00
|
|
|
|
|
2018-06-21 14:39:07 +00:00
|
|
|
|
Before a [`<webview>`][webview-tag] tag is attached, Electron will fire the
|
2018-01-29 02:19:49 +00:00
|
|
|
|
`will-attach-webview` event on the hosting `webContents`. Use the event to
|
2018-07-31 18:40:26 +00:00
|
|
|
|
prevent the creation of `webViews` with possibly insecure options.
|
2018-01-29 02:19:49 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
```js title='main.js (Main Process)'
|
2018-01-29 02:19:49 +00:00
|
|
|
|
app.on('web-contents-created', (event, contents) => {
|
|
|
|
|
contents.on('will-attach-webview', (event, webPreferences, params) => {
|
|
|
|
|
// Strip away preload scripts if unused or verify their location is legitimate
|
|
|
|
|
delete webPreferences.preload
|
|
|
|
|
|
2018-01-30 00:01:05 +00:00
|
|
|
|
// Disable Node.js integration
|
2018-01-29 02:19:49 +00:00
|
|
|
|
webPreferences.nodeIntegration = false
|
|
|
|
|
|
|
|
|
|
// Verify URL being loaded
|
2019-02-27 18:09:38 +00:00
|
|
|
|
if (!params.src.startsWith('https://example.com/')) {
|
2018-01-29 02:19:49 +00:00
|
|
|
|
event.preventDefault()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
Again, this list merely minimizes the risk, but does not remove it. If your goal
|
2016-05-10 08:41:16 +00:00
|
|
|
|
is to display a website, a browser will be a more secure option.
|
2018-01-29 20:34:46 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
### 13. Disable or limit navigation
|
2018-07-31 18:40:26 +00:00
|
|
|
|
|
|
|
|
|
If your app has no need to navigate or only needs to navigate to known pages,
|
|
|
|
|
it is a good idea to limit navigation outright to that known scope, disallowing
|
|
|
|
|
any other kinds of navigation.
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### Why?
|
2018-07-31 18:40:26 +00:00
|
|
|
|
|
|
|
|
|
Navigation is a common attack vector. If an attacker can convince your app to
|
|
|
|
|
navigate away from its current page, they can possibly force your app to open
|
|
|
|
|
web sites on the Internet. Even if your `webContents` are configured to be more
|
|
|
|
|
secure (like having `nodeIntegration` disabled or `contextIsolation` enabled),
|
|
|
|
|
getting your app to open a random web site will make the work of exploiting your
|
|
|
|
|
app a lot easier.
|
|
|
|
|
|
|
|
|
|
A common attack pattern is that the attacker convinces your app's users to
|
|
|
|
|
interact with the app in such a way that it navigates to one of the attacker's
|
|
|
|
|
pages. This is usually done via links, plugins, or other user-generated content.
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### How?
|
2018-07-31 18:40:26 +00:00
|
|
|
|
|
|
|
|
|
If your app has no need for navigation, you can call `event.preventDefault()`
|
|
|
|
|
in a [`will-navigate`][will-navigate] handler. If you know which pages your app
|
|
|
|
|
might navigate to, check the URL in the event handler and only let navigation
|
|
|
|
|
occur if it matches the URLs you're expecting.
|
|
|
|
|
|
|
|
|
|
We recommend that you use Node's parser for URLs. Simple string comparisons can
|
2019-02-27 18:09:38 +00:00
|
|
|
|
sometimes be fooled - a `startsWith('https://example.com')` test would let
|
|
|
|
|
`https://example.com.attacker.com` through.
|
2018-07-31 18:40:26 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
```js title='main.js (Main Process)'
|
2023-06-05 07:26:26 +00:00
|
|
|
|
const { URL } = require('url')
|
|
|
|
|
const { app } = require('electron')
|
2018-07-31 18:40:26 +00:00
|
|
|
|
|
|
|
|
|
app.on('web-contents-created', (event, contents) => {
|
|
|
|
|
contents.on('will-navigate', (event, navigationUrl) => {
|
|
|
|
|
const parsedUrl = new URL(navigationUrl)
|
|
|
|
|
|
2019-02-27 18:09:38 +00:00
|
|
|
|
if (parsedUrl.origin !== 'https://example.com') {
|
2018-07-31 18:40:26 +00:00
|
|
|
|
event.preventDefault()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
### 14. Disable or limit creation of new windows
|
2018-07-31 18:40:26 +00:00
|
|
|
|
|
|
|
|
|
If you have a known set of windows, it's a good idea to limit the creation of
|
|
|
|
|
additional windows in your app.
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### Why?
|
2018-07-31 18:40:26 +00:00
|
|
|
|
|
|
|
|
|
Much like navigation, the creation of new `webContents` is a common attack
|
|
|
|
|
vector. Attackers attempt to convince your app to create new windows, frames,
|
|
|
|
|
or other renderer processes with more privileges than they had before; or
|
|
|
|
|
with pages opened that they couldn't open before.
|
|
|
|
|
|
|
|
|
|
If you have no need to create windows in addition to the ones you know you'll
|
|
|
|
|
need to create, disabling the creation buys you a little bit of extra
|
|
|
|
|
security at no cost. This is commonly the case for apps that open one
|
|
|
|
|
`BrowserWindow` and do not need to open an arbitrary number of additional
|
|
|
|
|
windows at runtime.
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### How?
|
2018-07-31 18:40:26 +00:00
|
|
|
|
|
2020-11-10 17:06:03 +00:00
|
|
|
|
[`webContents`][web-contents] will delegate to its [window open
|
|
|
|
|
handler][window-open-handler] before creating new windows. The handler will
|
|
|
|
|
receive, amongst other parameters, the `url` the window was requested to open
|
|
|
|
|
and the options used to create it. We recommend that you register a handler to
|
|
|
|
|
monitor the creation of windows, and deny any unexpected window creation.
|
2018-07-31 18:40:26 +00:00
|
|
|
|
|
2023-06-05 07:26:26 +00:00
|
|
|
|
```js title='main.js (Main Process)' @ts-type={isSafeForExternalOpen:(url:string)=>boolean}
|
|
|
|
|
const { app, shell } = require('electron')
|
2018-07-31 18:40:26 +00:00
|
|
|
|
|
|
|
|
|
app.on('web-contents-created', (event, contents) => {
|
2020-11-10 17:06:03 +00:00
|
|
|
|
contents.setWindowOpenHandler(({ url }) => {
|
2018-07-31 18:40:26 +00:00
|
|
|
|
// In this example, we'll ask the operating system
|
|
|
|
|
// to open this event's url in the default browser.
|
2020-11-10 17:06:03 +00:00
|
|
|
|
//
|
|
|
|
|
// See the following item for considerations regarding what
|
|
|
|
|
// URLs should be allowed through to shell.openExternal.
|
|
|
|
|
if (isSafeForExternalOpen(url)) {
|
|
|
|
|
setImmediate(() => {
|
|
|
|
|
shell.openExternal(url)
|
|
|
|
|
})
|
|
|
|
|
}
|
2018-07-31 18:40:26 +00:00
|
|
|
|
|
2020-11-10 17:06:03 +00:00
|
|
|
|
return { action: 'deny' }
|
2018-07-31 18:40:26 +00:00
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
### 15. Do not use `shell.openExternal` with untrusted content
|
2019-02-27 18:09:38 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
The shell module's [`openExternal`][open-external] API allows opening a given
|
|
|
|
|
protocol URI with the desktop's native utilities. On macOS, for instance, this
|
|
|
|
|
function is similar to the `open` terminal command utility and will open the
|
|
|
|
|
specific application based on the URI and filetype association.
|
2019-02-27 18:09:38 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### Why?
|
2019-02-27 18:09:38 +00:00
|
|
|
|
|
|
|
|
|
Improper use of [`openExternal`][open-external] can be leveraged to compromise
|
|
|
|
|
the user's host. When openExternal is used with untrusted content, it can be
|
|
|
|
|
leveraged to execute arbitrary commands.
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### How?
|
2019-02-27 18:09:38 +00:00
|
|
|
|
|
2023-06-05 07:26:26 +00:00
|
|
|
|
```js title='main.js (Main Process)' @ts-type={USER_CONTROLLED_DATA_HERE:string}
|
2019-02-27 18:09:38 +00:00
|
|
|
|
// Bad
|
|
|
|
|
const { shell } = require('electron')
|
|
|
|
|
shell.openExternal(USER_CONTROLLED_DATA_HERE)
|
|
|
|
|
```
|
2020-11-05 22:12:43 +00:00
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
```js title='main.js (Main Process)'
|
2019-02-27 18:09:38 +00:00
|
|
|
|
// Good
|
|
|
|
|
const { shell } = require('electron')
|
|
|
|
|
shell.openExternal('https://example.com/index.html')
|
|
|
|
|
```
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
### 16. Use a current version of Electron
|
2019-09-14 01:12:14 +00:00
|
|
|
|
|
|
|
|
|
You should strive for always using the latest available version of Electron.
|
|
|
|
|
Whenever a new major version is released, you should attempt to update your
|
|
|
|
|
app as quickly as possible.
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### Why?
|
2019-09-14 01:12:14 +00:00
|
|
|
|
|
|
|
|
|
An application built with an older version of Electron, Chromium, and Node.js
|
|
|
|
|
is an easier target than an application that is using more recent versions of
|
|
|
|
|
those components. Generally speaking, security issues and exploits for older
|
|
|
|
|
versions of Chromium and Node.js are more widely available.
|
|
|
|
|
|
|
|
|
|
Both Chromium and Node.js are impressive feats of engineering built by
|
|
|
|
|
thousands of talented developers. Given their popularity, their security is
|
|
|
|
|
carefully tested and analyzed by equally skilled security researchers. Many of
|
|
|
|
|
those researchers [disclose vulnerabilities responsibly][responsible-disclosure],
|
|
|
|
|
which generally means that researchers will give Chromium and Node.js some time
|
|
|
|
|
to fix issues before publishing them. Your application will be more secure if
|
|
|
|
|
it is running a recent version of Electron (and thus, Chromium and Node.js) for
|
|
|
|
|
which potential security issues are not as widely known.
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
#### How?
|
|
|
|
|
|
|
|
|
|
Migrate your app one major version at a time, while referring to Electron's
|
|
|
|
|
[Breaking Changes][breaking-changes] document to see if any code needs to
|
|
|
|
|
be updated.
|
|
|
|
|
|
2022-03-23 00:45:23 +00:00
|
|
|
|
### 17. Validate the `sender` of all IPC messages
|
|
|
|
|
|
|
|
|
|
You should always validate incoming IPC messages `sender` property to ensure you
|
|
|
|
|
aren't performing actions or sending information to untrusted renderers.
|
|
|
|
|
|
|
|
|
|
#### Why?
|
|
|
|
|
|
|
|
|
|
All Web Frames can in theory send IPC messages to the main process, including
|
|
|
|
|
iframes and child windows in some scenarios. If you have an IPC message that returns
|
|
|
|
|
user data to the sender via `event.reply` or performs privileged actions that the renderer
|
|
|
|
|
can't natively, you should ensure you aren't listening to third party web frames.
|
|
|
|
|
|
|
|
|
|
You should be validating the `sender` of **all** IPC messages by default.
|
|
|
|
|
|
|
|
|
|
#### How?
|
|
|
|
|
|
2023-06-05 07:26:26 +00:00
|
|
|
|
```js title='main.js (Main Process)' @ts-type={getSecrets:()=>unknown}
|
2022-03-23 00:45:23 +00:00
|
|
|
|
// Bad
|
|
|
|
|
ipcMain.handle('get-secrets', () => {
|
2023-05-15 07:58:35 +00:00
|
|
|
|
return getSecrets()
|
|
|
|
|
})
|
2022-03-23 00:45:23 +00:00
|
|
|
|
|
|
|
|
|
// Good
|
|
|
|
|
ipcMain.handle('get-secrets', (e) => {
|
2023-05-15 07:58:35 +00:00
|
|
|
|
if (!validateSender(e.senderFrame)) return null
|
|
|
|
|
return getSecrets()
|
|
|
|
|
})
|
2022-03-23 00:45:23 +00:00
|
|
|
|
|
2023-05-15 07:58:35 +00:00
|
|
|
|
function validateSender (frame) {
|
2022-03-23 00:45:23 +00:00
|
|
|
|
// Value the host of the URL using an actual URL parser and an allowlist
|
2023-05-15 07:58:35 +00:00
|
|
|
|
if ((new URL(frame.url)).host === 'electronjs.org') return true
|
|
|
|
|
return false
|
2022-03-23 00:45:23 +00:00
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2023-11-09 18:23:52 +00:00
|
|
|
|
### 18. Avoid usage of the `file://` protocol and prefer usage of custom protocols
|
|
|
|
|
|
|
|
|
|
You should serve local pages from a custom protocol instead of the `file://` protocol.
|
|
|
|
|
|
|
|
|
|
#### Why?
|
|
|
|
|
|
|
|
|
|
The `file://` protocol gets more privileges in Electron than in a web browser and even in
|
|
|
|
|
browsers it is treated differently to http/https URLs. Using a custom protocol allows you
|
|
|
|
|
to be more aligned with classic web url behavior while retaining even more control about
|
|
|
|
|
what can be loaded and when.
|
|
|
|
|
|
|
|
|
|
Pages running on `file://` have unilateral access to every file on your machine meaning
|
|
|
|
|
that XSS issues can be used to load arbitrary files from the users machine. Using a custom
|
|
|
|
|
protocol prevents issues like this as you can limit the protocol to only serving a specific
|
|
|
|
|
set of files.
|
|
|
|
|
|
|
|
|
|
#### How?
|
|
|
|
|
|
|
|
|
|
Follow the [`protocol.handle`](../api/protocol.md#protocolhandlescheme-handler) examples to
|
|
|
|
|
learn how to serve files / content from a custom protocol.
|
|
|
|
|
|
2022-02-16 17:47:32 +00:00
|
|
|
|
[breaking-changes]: ../breaking-changes.md
|
2018-01-30 00:01:05 +00:00
|
|
|
|
[browser-window]: ../api/browser-window.md
|
2018-06-21 14:39:07 +00:00
|
|
|
|
[webview-tag]: ../api/webview-tag.md
|
2023-12-13 21:01:03 +00:00
|
|
|
|
[web-contents-view]: ../api/web-contents-view.md
|
|
|
|
|
[responsible-disclosure]: https://en.wikipedia.org/wiki/Responsible_disclosure
|
2018-07-31 18:40:26 +00:00
|
|
|
|
[web-contents]: ../api/web-contents.md
|
2020-11-19 07:06:32 +00:00
|
|
|
|
[window-open-handler]: ../api/web-contents.md#contentssetwindowopenhandlerhandler
|
2018-08-09 15:04:03 +00:00
|
|
|
|
[will-navigate]: ../api/web-contents.md#event-will-navigate
|
2020-10-20 01:46:27 +00:00
|
|
|
|
[open-external]: ../api/shell.md#shellopenexternalurl-options
|