docs: Improved security doc, particularly around isolation and tool (#16703)

* Improved security doc, particularly around isolation and tool

* Fixes as suggested by @ckerr

* libcc update

* fixing lint stuff
This commit is contained in:
Luca Carettoni 2019-02-27 19:09:38 +01:00 коммит произвёл Samuel Attard
Родитель a07cb2afd7
Коммит 1bbb47be5b
1 изменённых файлов: 94 добавлений и 28 удалений

Просмотреть файл

@ -40,19 +40,46 @@ interested in hearing more about specific use cases from the people that build
things on top of Electron. Pull requests and contributions supporting this
effort are always very welcome.
## Ignoring Above Advice
## Security Is Everyone's Responsibility
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
inside a [`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.
It is important to remember that the security of your Electron application is
the result of the overall security of the framework foundation
(*Chromium*, *Node.js*), Electron itself, all NPM dependencies and
your code. As such, it is your responsibility to follow a few important best
practices:
* **Keep your application up-to-date with the latest Electron framework release.**
When releasing your product, youre 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
version, you ensure that critical vulnerabilities (such as *nodeIntegration bypasses*)
are already patched and cannot be exploited in your application.
* **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,
your application security could be in jeopardy.
* **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
to adopt secure software development best practices and perform security testing.
## Isolation For Untrusted Content
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.
> :warning: Under no circumstances should you load and execute remote code with
Node.js integration enabled. Instead, use only local files (packaged together
with your application) to execute Node.js code. To display remote content, use
the [`<webview>`][webview-tag] tag and make sure to disable the `nodeIntegration`.
the [`<webview>`][webview-tag] tag or [`BrowserView`][browser-view], make sure
to disable the `nodeIntegration` and enable `contextIsolation`.
## Electron Security Warnings
@ -66,8 +93,7 @@ either `process.env` or the `window` object.
## Checklist: Security Recommendations
This is not bulletproof, but at the least, you should follow these steps to
improve the security of your application.
You should at least follow these steps to improve the security of your application:
1. [Only load secure content](#1-only-load-secure-content)
2. [Disable the Node.js integration in all renderers that display remote content](#2-disable-nodejs-integration-for-remote-content)
@ -82,6 +108,14 @@ improve the security of your application.
11. [`<webview>`: Verify options and params](#11-verify-webview-options-before-creation)
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)
To automate the detection of misconfigurations and insecure patterns, it is
possible to use
[electronegativity](https://github.com/doyensec/electronegativity). For
additional details on potential weaknesses and implementation bugs when
developing applications using Electron, please refer to this [guide for
developers and auditors](https://doyensec.com/resources/us-17-Carettoni-Electronegativity-A-Study-Of-Electron-Security-wp.pdf)
## 1) Only Load Secure Content
@ -106,20 +140,20 @@ like `HTTP`. Similarly, we recommend the use of `WSS` over `WS`, `FTPS` over
```js
// Bad
browserWindow.loadURL('http://my-website.com')
browserWindow.loadURL('http://example.com')
// Good
browserWindow.loadURL('https://my-website.com')
browserWindow.loadURL('https://example.com')
```
```html
<!-- Bad -->
<script crossorigin src="http://cdn.com/react.js"></script>
<link rel="stylesheet" href="http://cdn.com/style.css">
<script crossorigin src="http://example.com/react.js"></script>
<link rel="stylesheet" href="http://example.com/style.css">
<!-- Good -->
<script crossorigin src="https://cdn.com/react.js"></script>
<link rel="stylesheet" href="https://cdn.com/style.css">
<script crossorigin src="https://example.com/react.js"></script>
<link rel="stylesheet" href="https://example.com/style.css">
```
@ -133,7 +167,7 @@ for an attacker to harm your users should they gain the ability to execute
JavaScript on your website.
After this, you can grant additional permissions for specific hosts. For example,
if you are opening a BrowserWindow pointed at `https://my-website.com/", you can
if you are opening a BrowserWindow pointed at `https://example.com/", you can
give that website exactly the abilities it needs, but no more.
### Why?
@ -150,7 +184,7 @@ so-called "Remote Code Execution" (RCE) attack.
```js
// Bad
const mainWindow = new BrowserWindow()
mainWindow.loadURL('https://my-website.com')
mainWindow.loadURL('https://example.com')
```
```js
@ -158,11 +192,12 @@ mainWindow.loadURL('https://my-website.com')
const mainWindow = new BrowserWindow({
webPreferences: {
nodeIntegration: false,
nodeIntegrationInWorker: false,
preload: './preload.js'
}
})
mainWindow.loadURL('https://my-website.com')
mainWindow.loadURL('https://example.com')
```
```html
@ -201,6 +236,9 @@ practice, that means that global objects like `Array.prototype.push` or
Electron uses the same technology as Chromium's [Content Scripts](https://developer.chrome.com/extensions/content_scripts#execution-environment)
to enable this behavior.
Even when you use `nodeIntegration: false` to enforce strong isolation and
prevent the use of Node primitives, `contextIsolation` must also be used.
### Why?
Context isolation allows each the scripts on running in the renderer to make
@ -209,7 +247,7 @@ the scripts in the Electron API or the preload script.
While still an experimental Electron feature, context isolation adds an
additional layer of security. It creates a new JavaScript world for Electron
APIs and preload scripts.
APIs and preload scripts, which mitigates so-called "Prototype Pollution" attacks.
At the same time, preload scripts still have access to the `document` and
`window` objects. In other words, you're getting a decent return on a likely
@ -279,7 +317,7 @@ session
}
// Verify URL
if (!url.startsWith('https://my-website.com/')) {
if (!url.startsWith('https://example.com/')) {
// Denies the permissions request
return callback(false)
}
@ -337,20 +375,20 @@ be enabled by any website you load inside Electron.
### Why?
CSP allows the server serving content to restrict and control the resources
Electron can load for that given web page. `https://your-page.com` should
Electron can load for that given web page. `https://example.com` should
be allowed to load scripts from the origins you defined while scripts from
`https://evil.attacker.com` should not be allowed to run. Defining a CSP is an
easy way to improve your application's security.
The following CSP will allow Electron to execute scripts from the current
website and from `apis.mydomain.com`.
website and from `apis.example.com`.
```txt
// Bad
Content-Security-Policy: '*'
// Good
Content-Security-Policy: script-src 'self' https://apis.mydomain.com
Content-Security-Policy: script-src 'self' https://apis.example.com
```
### CSP HTTP Header
@ -551,7 +589,7 @@ app.on('web-contents-created', (event, contents) => {
webPreferences.nodeIntegration = false
// Verify URL being loaded
if (!params.src.startsWith('https://yourapp.com/')) {
if (!params.src.startsWith('https://example.com/')) {
event.preventDefault()
}
})
@ -588,8 +626,8 @@ 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
sometimes be fooled - a `startsWith('https://google.com')` test would let
`https://google.com.attacker.com` through.
sometimes be fooled - a `startsWith('https://example.com')` test would let
`https://example.com.attacker.com` through.
```js
const URL = require('url').URL
@ -598,7 +636,7 @@ app.on('web-contents-created', (event, contents) => {
contents.on('will-navigate', (event, navigationUrl) => {
const parsedUrl = new URL(navigationUrl)
if (parsedUrl.origin !== 'https://my-own-server.com') {
if (parsedUrl.origin !== 'https://example.com') {
event.preventDefault()
}
})
@ -645,9 +683,37 @@ app.on('web-contents-created', (event, contents) => {
})
```
## 14) Do not use `openExternal` with untrusted content
Shell's [`openExternal`][open-external] 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.
### Why?
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.
### How?
```js
// Bad
const { shell } = require('electron')
shell.openExternal(USER_CONTROLLED_DATA_HERE)
```
```js
// Good
const { shell } = require('electron')
shell.openExternal('https://example.com/index.html')
```
[browser-window]: ../api/browser-window.md
[browser-view]: ../api/browser-view.md
[webview-tag]: ../api/webview-tag.md
[web-contents]: ../api/web-contents.md
[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