Merge pull request #8983 from electron/sandbox-initial-documentation

Add initial documentation for `sandbox` option.
This commit is contained in:
Kevin Sawicki 2017-03-27 10:16:24 -07:00 committed by GitHub
commit ad5a48d255
2 changed files with 193 additions and 1 deletions

View file

@ -225,6 +225,13 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
When node integration is turned off, the preload script can reintroduce
Node global symbols back to the global scope. See example
[here](process.md#event-loaded).
* `sandbox` Boolean (optional) - If set, this will sandbox the renderer
associated with the window, making it compatible with the Chromium
OS-level sandbox and disabling the Node.js engine. This is not the same as
the `nodeIntegration` option and the APIs available to the preload script
are more limited. Read more about the option [here](sandbox-option.md).
**Note:** This option is currently experimental and may change or be
removed in future Electron releases.
* `session` [Session](session.md#class-session) (optional) - Sets the session used by the
page. Instead of passing the Session object directly, you can also choose to
use the `partition` option instead, which accepts a partition string. When
@ -282,7 +289,6 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
window. Defaults to `false`. See the
[offscreen rendering tutorial](../tutorial/offscreen-rendering.md) for
more details.
* `sandbox` Boolean (optional) - Whether to enable Chromium OS-level sandbox.
* `contextIsolation` Boolean (optional) - Whether to run Electron APIs and
the specified `preload` script in a separate JavaScript context. Defaults
to `false`. The context that the `preload` script runs in will still

186
docs/api/sandbox-option.md Normal file
View file

@ -0,0 +1,186 @@
# `sandbox` Option
> Create a browser window with renderer that can run inside chromium OS sandbox.
One of chromium key security features is that all blink rendering/javascript
code is confined in a sandbox. This sandbox uses OS-specific features to ensure
that exploits in the renderer process cannot harm the system.
In other words, when the sandbox is enabled, the renderers can only make changes
to the system by delegating tasks to the main process via IPC.
[Here's](https://www.chromium.org/developers/design-documents/sandbox) more
information about the sandbox.
Since a major feature in electron is the ability to run node.js in the
renderer process(making it easier to develop desktop applications using only web
technologies), the sandbox has to disabled by electron. One of the reasons is
that most node.js APIs require system access. `require()` for example, is not
possible without file system permissions, which are unavailable in a sandboxed
environment.
Usually this is not a problem for desktop applications since the code is always
trusted, but it makes electron less secure than chromium for displaying
untrusted web content. For applications that require more security, the
`sandbox` flag will force electron to spawn a classic chromium renderer that is
compatible with the sandbox.
A sandboxed renderer doesn't have a node.js environment running and doesn't
expose javascript APIs to client code. The only exception is the preload script,
which has access to a subset of electron renderer API.
Another difference is that sandboxed renderers don't modify any of the default
javascript APIs. Consequently, some APIs such as `window.open` will work as they
do in chromium(no `BrowserWindowProxy`).
## Example
Create a sandboxed window, simply pass `sandbox: true` to `webPreferences`:
```js
let win
app.on('ready', () => {
win = new BrowserWindow({
webPreferences: {
sandbox: true
}
})
w.loadURL('http://google.com')
})
```
This alone won't enable the OS-enforced sandbox. To use it, the
`--enable-sandbox` command-line argument must be passed to electron, which will
force `sandbox: true` to all BrowserWindow instances.
```js
let win
app.on('ready', () => {
// no need to pass `sandbox: true` since `--enable-sandbox` was enabled.
win = new BrowserWindow()
w.loadURL('http://google.com')
})
```
Note that it is not enough to call
`app.commandLine.appendSwitch('--enable-sandbox')`, as electron/node startup
code runs after it is possible to make changes to chromium sandbox settings. The
switch must be passed to electron command-line:
```
electron --enable-sandbox app.js
```
It is not possible to have the OS sandbox active only for some renderers, if
`--enable-sandbox` is enabled, normal electron windows cannot be created.
If you need to mix sandboxed and non-sandboxed renderers in one application,
simply omit the `--enable-sandbox` argument. Without this argument, windows
created with `sandbox: true` will still have node.js disabled and communicate
only via IPC, which by itself is already a gain from security POV.
## Preload
An app can make customizations to sandboxed renderers using a preload script.
Here's an example:
```js
let win
app.on('ready', () => {
win = new BrowserWindow({
webPreferences: {
sandbox: true,
preload: 'preload.js'
}
})
w.loadURL('http://google.com')
})
```
and preload.js:
```js
// This file is loaded whenever a javascript context is created. It runs in a
// private scope that can access a subset of electron renderer APIs. We must be
// careful to not leak any objects into the global scope!
const fs = require('fs')
const {ipcRenderer} = require('electron')
// read a configuration file using the `fs` module
const buf = fs.readFileSync('allowed-popup-urls.json')
const allowedUrls = JSON.parse(buf.toString('utf8'))
const defaultWindowOpen = window.open
function customWindowOpen (url, ...args) {
if (allowedUrls.indexOf(url) === -1) {
ipcRenderer.sendSync('blocked-popup-notification', location.origin, url)
return null
}
return defaultWindowOpen(url, ...args)
}
window.open = customWindowOpen
```
Important things to notice in the preload script:
- Even though the sandboxed renderer doesn't have node.js running, it still has
access to a limited node-like environment:`Buffer`, `process`, `setImmediate`
and `require` are available.
- The preload can indirectly access all APIs from the main process through the
`remote` and `ipcRenderer` modules. This is how `fs`(used above) and other
modules are implemented: They are proxies to remote counterparts in the main
process.
- The preload must be contained in a single script, but it is possible to have
complex preload code composed with multiple modules by using a tool like
browserify, as explained below. In fact, browserify is already used by
electron to provide a node-like environment to the preload script.
To create a browserify bundle and use it as a preload script, something like
the following should be used:
browserify preload/index.js \
-x electron \
-x fs \
--insert-global-vars=__filename,__dirname -o preload.js
The `-x` flag should be used with any required module that is already exposed in
the preload scope, and tells browserify to use the enclosing `require` function
for it. `--insert-global-vars` will ensure that `process`,`Buffer` and
`setImmediate` are also taken from the enclosing scope(normally browserify
injects code for those).
Currently the `require` function provided in the preload scope exposes the
following modules:
- `child_process`
- `electron`(crashReporter, remote and ipcRenderer)
- `fs`
- `os`
- `timers`
- `url`
More may be added as needed to expose more electron APIs in the sandbox, but any
module in the main process can already be used through
`electron.remote.require`.
## Status
Please use the `sandbox` option with care, as it still is an experimental
feature. We are still not aware of the security implications of exposing some
electron renderer APIs to the preload script, but here are some things to
consider before rendering untrusted content:
- A preload script can accidentaly leak privileged APIs to untrusted code.
- Some bug in V8 engine may allow malicious code to access the renderer preload
APIs, effectively granting full access to the system through the `remote`
module.
Since renderering untrusted content in electron is still uncharted territory,
the APIs exposed to the sandbox preload script should be considered more
unstable than the rest of electron APIs, and may have breaking changes to fix
security issues.
One planned enhancement that should greatly increase security is to block IPC
messages from sandboxed renderers by default, allowing the main process
explicitly define a set of messages the renderer is allowed to send.