Skip to content

Commit a99cc96

Browse files
felixriesebergckerr
authored andcommitted
📝 Update security docs: will-navigate, new-window (electron#13884)
1 parent 31ac89f commit a99cc96

1 file changed

Lines changed: 90 additions & 2 deletions

File tree

docs/tutorial/security.md

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ improve the security of your application.
8181
10. [Do not use `enableBlinkFeatures`](#10-do-not-use-enableblinkfeatures)
8282
11. [`<webview>`: Do not use `allowpopups`](#11-do-not-use-allowpopups)
8383
12. [`<webview>`: Verify options and params](#12-verify-webview-options-before-creation)
84-
84+
13. [Disable or limit navigation](#13-disable-or-limit-navigation)
85+
14. [Disable or limit creation of new windows](#13-disable-or-limit-creation-of-new-windows)
8586

8687
## 1) Only Load Secure Content
8788

@@ -557,7 +558,7 @@ for newly created [`<webview>`][webview-tag] tags.
557558

558559
Before a [`<webview>`][webview-tag] tag is attached, Electron will fire the
559560
`will-attach-webview` event on the hosting `webContents`. Use the event to
560-
prevent the creation of webviews with possibly insecure options.
561+
prevent the creation of `webViews` with possibly insecure options.
561562

562563
```js
563564
app.on('web-contents-created', (event, contents) => {
@@ -580,6 +581,93 @@ app.on('web-contents-created', (event, contents) => {
580581
Again, this list merely minimizes the risk, it does not remove it. If your goal
581582
is to display a website, a browser will be a more secure option.
582583

584+
## 13) Disable or limit navigation
585+
586+
If your app has no need to navigate or only needs to navigate to known pages,
587+
it is a good idea to limit navigation outright to that known scope, disallowing
588+
any other kinds of navigation.
589+
590+
### Why?
591+
592+
Navigation is a common attack vector. If an attacker can convince your app to
593+
navigate away from its current page, they can possibly force your app to open
594+
web sites on the Internet. Even if your `webContents` are configured to be more
595+
secure (like having `nodeIntegration` disabled or `contextIsolation` enabled),
596+
getting your app to open a random web site will make the work of exploiting your
597+
app a lot easier.
598+
599+
A common attack pattern is that the attacker convinces your app's users to
600+
interact with the app in such a way that it navigates to one of the attacker's
601+
pages. This is usually done via links, plugins, or other user-generated content.
602+
603+
### How?
604+
605+
If your app has no need for navigation, you can call `event.preventDefault()`
606+
in a [`will-navigate`][will-navigate] handler. If you know which pages your app
607+
might navigate to, check the URL in the event handler and only let navigation
608+
occur if it matches the URLs you're expecting.
609+
610+
We recommend that you use Node's parser for URLs. Simple string comparisons can
611+
sometimes be fooled - a `startsWith('https://google.com')` test would let
612+
`https://google.com.attacker.com` through.
613+
614+
```js
615+
const URL = require('url')
616+
617+
app.on('web-contents-created', (event, contents) => {
618+
contents.on('will-navigate', (event, navigationUrl) => {
619+
const parsedUrl = new URL(navigationUrl)
620+
621+
if (url.hostname !== 'my-own-server.com') {
622+
event.preventDefault()
623+
}
624+
})
625+
})
626+
```
627+
628+
## 14) Disable or limit creation of new windows
629+
630+
If you have a known set of windows, it's a good idea to limit the creation of
631+
additional windows in your app.
632+
633+
### Why?
634+
635+
Much like navigation, the creation of new `webContents` is a common attack
636+
vector. Attackers attempt to convince your app to create new windows, frames,
637+
or other renderer processes with more privileges than they had before; or
638+
with pages opened that they couldn't open before.
639+
640+
If you have no need to create windows in addition to the ones you know you'll
641+
need to create, disabling the creation buys you a little bit of extra
642+
security at no cost. This is commonly the case for apps that open one
643+
`BrowserWindow` and do not need to open an arbitrary number of additional
644+
windows at runtime.
645+
646+
### How?
647+
648+
[`webContents`][web-contents] will emit the [`new-window`][new-window] event
649+
before creating new windows. That event will be passed, amongst other
650+
parameters, the `url` the window was requested to open and the options used to
651+
create it. We recommend that you use the event to scrutinize the creation of
652+
windows, limiting it to only what you need.
653+
654+
```js
655+
const { shell } = require('electron')
656+
657+
app.on('web-contents-created', (event, contents) => {
658+
contents.on('new-window', (event, navigationUrl) => {
659+
// In this example, we'll ask the operating system
660+
// to open this event's url in the default browser.
661+
event.preventDefault()
662+
663+
shell.openExternal(navigationUrl)
664+
})
665+
})
666+
```
667+
583668
[browser-window]: ../api/browser-window.md
584669
[browser-view]: ../api/browser-view.md
585670
[webview-tag]: ../api/webview-tag.md
671+
[web-contents]: ../api/web-contents.md
672+
[new-window]: ../api/web-contents#event-new-window
673+
[will-navigate]: ../api/web-contents#event-will-navigate

0 commit comments

Comments
 (0)