📝 General cleanup
This commit is contained in:
parent
c4dc8dacbf
commit
fb8606dd0c
1 changed files with 77 additions and 64 deletions
|
@ -1,19 +1,19 @@
|
||||||
# Security, Native Capabilities, and Your Responsibility
|
# Security, Native Capabilities, and Your Responsibility
|
||||||
|
|
||||||
As web developers, we usually enjoy the strong security net of the browser - the
|
As web developers, we usually enjoy the strong security net of the browser -
|
||||||
risks associated with the code we write are relatively small. Our websites are
|
the risks associated with the code we write are relatively small. Our websites
|
||||||
granted limited powers in a sandbox, and we trust that our users enjoy a browser
|
are granted limited powers in a sandbox, and we trust that our users enjoy a
|
||||||
built by a large team of engineers that is able to quickly respond to newly
|
browser built by a large team of engineers that is able to quickly respond to
|
||||||
discovered security threats.
|
newly discovered security threats.
|
||||||
|
|
||||||
When working with Electron, it is important to understand that Electron is not
|
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
|
a web browser. It allows you to build feature-rich desktop applications with
|
||||||
familiar web technologies, but your code wields much greater power. JavaScript
|
familiar web technologies, but your code wields much greater power. JavaScript
|
||||||
can access the filesystem, user shell, and more. This allows you to build
|
can access the filesystem, user shell, and more. This allows you to build
|
||||||
high quality native applications, but the inherent security risks scale with the
|
high quality native applications, but the inherent security risks scale with
|
||||||
additional powers granted to your code.
|
the additional powers granted to your code.
|
||||||
|
|
||||||
With that in mind, be aware that displaying arbitrary content from untrusted
|
With that in mind, be aware that displaying arbitrary content from un-trusted
|
||||||
sources poses a severe security risk that Electron is not intended to handle.
|
sources poses a severe security risk that Electron is not intended to handle.
|
||||||
In fact, the most popular Electron apps (Atom, Slack, Visual Studio Code, etc)
|
In fact, the most popular Electron apps (Atom, Slack, Visual Studio Code, etc)
|
||||||
display primarily local content (or trusted, secure remote content without Node
|
display primarily local content (or trusted, secure remote content without Node
|
||||||
|
@ -34,8 +34,8 @@ contributions available today, Electron will often not be on the very latest
|
||||||
version of Chromium, lagging behind by either days or weeks.
|
version of Chromium, lagging behind by either days or weeks.
|
||||||
|
|
||||||
We feel that our current system of updating the Chromium component strikes an
|
We feel that our current system of updating the Chromium component strikes an
|
||||||
appropriate balance between the resources we have available and the needs of the
|
appropriate balance between the resources we have available and the needs of
|
||||||
majority of applications built on top of the framework. We definitely are
|
the majority of applications built on top of the framework. We definitely are
|
||||||
interested in hearing more about specific use cases from the people that build
|
interested in hearing more about specific use cases from the people that build
|
||||||
things on top of Electron. Pull requests and contributions supporting this
|
things on top of Electron. Pull requests and contributions supporting this
|
||||||
effort are always very welcome.
|
effort are always very welcome.
|
||||||
|
@ -44,15 +44,15 @@ effort are always very welcome.
|
||||||
|
|
||||||
A security issue exists whenever you receive code from a remote destination and
|
A security issue exists whenever you receive code from a remote destination and
|
||||||
execute it locally. As an example, consider a remote website being displayed
|
execute it locally. As an example, consider a remote website being displayed
|
||||||
inside a browser window. If an attacker somehow manages to change said content
|
inside a `BrowserWindow`. If an attacker somehow manages to change said content
|
||||||
(either by attacking the source directly, or by sitting between your app and
|
(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
|
the actual destination), they will be able to execute native code on the user's
|
||||||
machine.
|
machine.
|
||||||
|
|
||||||
> :warning: Under no circumstances should you load and execute remote code with
|
> :warning: Under no circumstances should you load and execute remote code with
|
||||||
Node.js integration enabled. Instead, use only local files (packaged together with
|
Node.js integration enabled. Instead, use only local files (packaged together
|
||||||
your application) to execute Node.js code. To display remote content, use the
|
with your application) to execute Node.js code. To display remote content, use
|
||||||
`webview` tag and make sure to disable the `nodeIntegration`.
|
the `webview` tag and make sure to disable the `nodeIntegration`.
|
||||||
|
|
||||||
#### Checklist: Security Recommendations
|
#### Checklist: Security Recommendations
|
||||||
|
|
||||||
|
@ -60,39 +60,34 @@ This is not bulletproof, but at the least, you should attempt the following:
|
||||||
|
|
||||||
* [Only display secure (https) content](#only-display-secure-content)
|
* [Only display secure (https) content](#only-display-secure-content)
|
||||||
* [Disable the Node integration in all renderers that display remote content](#disable-node-integration-for-remote-content)
|
* [Disable the Node integration in all renderers that display remote content](#disable-node-integration-for-remote-content)
|
||||||
(setting `nodeIntegration` to `false` in `webPreferences`)
|
* [Enable context isolation in all renderers that display remote content](#enable-context-isolation-for-remote-content)
|
||||||
* Enable context isolation in all renderers that display remote content
|
* [Use `ses.setPermissionRequestHandler()` in all sessions that load remote content](#handle-session-permission-requests-from-remote-content)
|
||||||
(setting `contextIsolation` to `true` in `webPreferences`)
|
* [Do not disable `webSecurity`](#do-not-disable-websecurity)
|
||||||
* Use `ses.setPermissionRequestHandler()` in all sessions that load remote content
|
* [Define a `Content-Security-Policy`](#define-a-content-security-policy)
|
||||||
* Do not disable `webSecurity`. Disabling it will disable the same-origin policy.
|
|
||||||
* Define a [`Content-Security-Policy`](http://www.html5rocks.com/en/tutorials/security/content-security-policy/)
|
|
||||||
, and use restrictive rules (i.e. `script-src 'self'`)
|
, and use restrictive rules (i.e. `script-src 'self'`)
|
||||||
* [Override and disable `eval`](https://github.com/nylas/N1/blob/0abc5d5defcdb057120d726b271933425b75b415/static/index.js#L6-L8)
|
* [Override and disable `eval`](#override-and-disable)
|
||||||
, which allows strings to be executed as code.
|
, which allows strings to be executed as code.
|
||||||
* Do not set `allowRunningInsecureContent` to true.
|
* [Do not set `allowRunningInsecureContent` to `true`](#do-not-set-allowRunningInsecureContent-to-true)
|
||||||
* Do not enable `experimentalFeatures` or `experimentalCanvasFeatures` unless
|
* [Do not enable experimental features](#do-not-enable-enable-experimental-features)
|
||||||
you know what you're doing.
|
* [Do not use `blinkFeatures`](#do-not-use-blinkfeatures)
|
||||||
* Do not use `blinkFeatures` unless you know what you're doing.
|
* [WebViews: Do not use `allowpopups`](#do-not-use-allowpopups)
|
||||||
* WebViews: Do not add the `nodeintegration` attribute.
|
|
||||||
* WebViews: Do not use `disablewebsecurity`
|
|
||||||
* WebViews: Do not use `allowpopups`
|
|
||||||
* WebViews: Do not use `insertCSS` or `executeJavaScript` with remote CSS/JS.
|
|
||||||
* [WebViews: Verify the options and params of all `<webview>` tags](#verify-webview-options-before-creation)
|
* [WebViews: Verify the options and params of all `<webview>` tags](#verify-webview-options-before-creation)
|
||||||
|
|
||||||
|
|
||||||
## Only Display Secure Content
|
## Only Display Secure Content
|
||||||
Any resources not included with your application should be loaded using a secure
|
|
||||||
protocol like `HTTPS`. Furthermore, avoid "mixed content", which occurs when the
|
Any resources not included with your application should be loaded using a
|
||||||
initial HTML is loaded over an `HTTPS` connection, but additional resources
|
secure protocol like `HTTPS`.
|
||||||
(scripts, stylesheets, etc) are loaded over an insecure connection.
|
|
||||||
|
|
||||||
### Why?
|
### Why?
|
||||||
|
|
||||||
`HTTPS` has three main benefits:
|
`HTTPS` has three main benefits:
|
||||||
|
|
||||||
1) It authenticates the remote server, ensuring that the host is actually who it
|
1) It authenticates the remote server, ensuring that the host is actually who
|
||||||
claims to be. When loading a resource from an `HTTPS` host, it prevents an
|
it claims to be. When loading a resource from an `HTTPS` host, it prevents
|
||||||
attacker from impersonating that host, thus ensuring that the computer your
|
an attacker from impersonating that host, thus ensuring that the computer
|
||||||
app's users are connecting to is actually the host you wanted them to connect
|
your app's users are connecting to is actually the host you wanted them to
|
||||||
to.
|
connect to.
|
||||||
2) It ensures data integrity, asserting that the data was not modified while in
|
2) It ensures data integrity, asserting that the data was not modified while in
|
||||||
transit between your application and the host.
|
transit between your application and the host.
|
||||||
3) It encryps the traffic between your user and the destination host, making it
|
3) It encryps the traffic between your user and the destination host, making it
|
||||||
|
@ -100,6 +95,7 @@ initial HTML is loaded over an `HTTPS` connection, but additional resources
|
||||||
the host.
|
the host.
|
||||||
|
|
||||||
### How?
|
### How?
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// Bad
|
// Bad
|
||||||
browserWindow.loadURL('http://my-website.com')
|
browserWindow.loadURL('http://my-website.com')
|
||||||
|
@ -118,29 +114,33 @@ browserWindow.loadURL('https://my-website.com')
|
||||||
<link rel="stylesheet" href="https://cdn.com/style.css">
|
<link rel="stylesheet" href="https://cdn.com/style.css">
|
||||||
```
|
```
|
||||||
|
|
||||||
## Disable Node Integration for Remote Content
|
|
||||||
It is paramount that you disable Node integration in any renderer (`BrowserWindow`,
|
|
||||||
`BrowserView`, or `WebView`) that loads remote content. The goal of disabling Node
|
|
||||||
integration is to limit the 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.
|
|
||||||
|
|
||||||
Disabling Node integration does not mean that you cannot grant additional powers
|
## Disable Node Integration for Remote Content
|
||||||
to the website you are loading. If you are opening a `BrowserWindow` pointed at
|
|
||||||
`https://my-website.com`, the goal is to give that website exactly the abilities
|
It is paramount that you disable Node integration in any renderer
|
||||||
it needs, but no more.
|
(`BrowserWindow`, `BrowserView`, or `WebView`) that loads remote content. The
|
||||||
|
goal of disabling Node integration is to limit the 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.
|
||||||
|
|
||||||
|
Disabling Node integration does not mean that you cannot grant additional
|
||||||
|
powers to the website you are loading. If you are opening a `BrowserWindow`
|
||||||
|
pointed at `https://my-website.com`, the goal is to give that website exactly
|
||||||
|
the abilities it needs, but no more.
|
||||||
|
|
||||||
### Why?
|
### Why?
|
||||||
|
|
||||||
A cross-site-scripting (XSS) attack becomes dramatically more dangerous if an
|
A cross-site-scripting (XSS) attack becomes dramatically more dangerous if an
|
||||||
attacker can jump out of the renderer process and execute code on the user's
|
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,
|
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
|
their power is usually limited to messing with the website that they are
|
||||||
on. However, in a renderer process with Node.js integration enabled, an XSS attack
|
executed on. However, in a renderer process with Node.js integration enabled,
|
||||||
becomes a whole different class of attack: A so-called "Remote Code Execution"
|
an XSS attack becomes a whole different class of attack: A so-called "Remote
|
||||||
(RCE) attack. Disabling Node.js integration limits the power of successful XSS
|
Code Execution" (RCE) attack. Disabling Node.js integration limits the power
|
||||||
attacks.
|
of successful XSS attacks.
|
||||||
|
|
||||||
### How?
|
### How?
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// Bad
|
// Bad
|
||||||
const mainWindow = new BrowserWindow()
|
const mainWindow = new BrowserWindow()
|
||||||
|
@ -157,13 +157,21 @@ const mainWindow = new BrowserWindow({
|
||||||
mainWindow.loadURL('https://my-website.com')
|
mainWindow.loadURL('https://my-website.com')
|
||||||
```
|
```
|
||||||
|
|
||||||
When disabling Node integration, you can still expose APIs to your
|
```html
|
||||||
website that do consume Node.js modules or features. Preload scripts continue to
|
<!-- Bad -->
|
||||||
have access to `require` and other Node.js features, allowing developers to expose
|
<webview nodeIntegration src="page.html"></webview>
|
||||||
a custom API to remotely loaded content.
|
|
||||||
|
|
||||||
In the following example preload script, the later loaded website will have access
|
<!-- Good -->
|
||||||
to a `window.readConfig()` method, but no Node.js features.
|
<webview src="page.html"></webview>
|
||||||
|
```
|
||||||
|
|
||||||
|
When disabling Node integration, you can still expose APIs to your website that
|
||||||
|
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
|
||||||
|
API to remotely loaded content.
|
||||||
|
|
||||||
|
In the following example preload script, the later loaded website will have
|
||||||
|
access to a `window.readConfig()` method, but no Node.js features.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const { readFileSync } = require('fs')
|
const { readFileSync } = require('fs')
|
||||||
|
@ -231,6 +239,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Handle Session Permission Requests From Remote Content
|
## Handle Session Permission Requests From Remote Content
|
||||||
|
|
||||||
You may have seen permission requests while using Chrome: They pop up whenever
|
You may have seen permission requests while using Chrome: They pop up whenever
|
||||||
|
@ -476,23 +485,27 @@ the ability to create new popups.
|
||||||
|
|
||||||
|
|
||||||
## Verify WebView Options Before Creation
|
## Verify WebView Options Before Creation
|
||||||
|
|
||||||
A WebView created in a renderer process that does not have Node.js integration
|
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
|
enabled will not be able to enable integration itself. However, a WebView will
|
||||||
always create an independent renderer process with its own `webPreferences`.
|
always create an independent renderer process with its own `webPreferences`.
|
||||||
|
|
||||||
It is a good idea to control the creation of new `WebViews` from the main process
|
It is a good idea to control the creation of new `WebViews` from the main
|
||||||
and to verify that their webPreferences do not disable security features.
|
process and to verify that their webPreferences do not disable security
|
||||||
|
features.
|
||||||
|
|
||||||
### Why?
|
### Why?
|
||||||
|
|
||||||
Since WebViews live in the DOM, they can be created by a script running on your
|
Since WebViews live in the DOM, they can be created by a script running on your
|
||||||
website even if Node integration is otherwise disabled.
|
website even if Node integration is otherwise disabled.
|
||||||
|
|
||||||
Electron enables developers to disable various security features that control
|
Electron enables developers to disable various security features that control
|
||||||
a renderer process. In most cases, developers do not need to disable any of those
|
a renderer process. In most cases, developers do not need to disable any of
|
||||||
features - and you should therefore not allow different configurations for newly
|
those features - and you should therefore not allow different configurations
|
||||||
created `<WebView>` tags.
|
for newly created `<WebView>` tags.
|
||||||
|
|
||||||
### How?
|
### How?
|
||||||
|
|
||||||
Before a `<WebView>` tag is attached, Electron will fire the
|
Before a `<WebView>` tag is attached, Electron will fire the
|
||||||
`will-attach-webview` event on the hosting `webContents`. Use the event to
|
`will-attach-webview` event on the hosting `webContents`. Use the event to
|
||||||
prevent the creation of WebViews with possibly insecure options.
|
prevent the creation of WebViews with possibly insecure options.
|
||||||
|
|
Loading…
Reference in a new issue