Security安全
For information on how to properly disclose an Electron vulnerability, see SECURITY.md.有关如何正确披露Electron漏洞的信息,请参阅SECURITY.md。
For upstream Chromium vulnerabilities: Electron keeps up to date with alternating Chromium releases. 对于上游铬脆弱性:Electron不断更新铬释放。For more information, see the Electron Release Timelines document.有关更多信息,请参阅Electron版本时间表文档。
Preface前言
As web developers, we usually enjoy the strong security net of the browser —
the risks associated with the code we write are relatively small. 作为web开发人员,我们通常享受浏览器强大的安全网络——与我们编写的代码相关的风险相对较小。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.网站在沙箱中被授予有限的权限,我们相信用户可以享受由一个大型工程师团队构建的浏览器,该团队能够快速响应新发现的安全威胁。
When working with Electron, it is important to understand that Electron is not a web browser. 使用Electron时,重要的是要理解Electron不是web浏览器。It allows you to build feature-rich desktop applications with familiar web technologies, but your code wields much greater power. 它允许您使用熟悉的web技术构建功能丰富的桌面应用程序,但您的代码拥有更强大的功能。JavaScript can access the filesystem, user shell, and more. JavaScript可以访问文件系统、用户shell等。This allows you to build high quality native applications, but the inherent security risks scale with the additional powers granted to your code.这允许您构建高质量的本机应用程序,但固有的安全风险会随着授予代码的附加功能而增加。
With that in mind, be aware that displaying arbitrary content from untrusted sources poses a severe security risk that Electron is not intended to handle. 考虑到这一点,请注意,显示来自不可信来源的任意内容会带来严重的安全风险,而Electron不打算处理这些风险。In fact, the most popular Electron apps (Atom, Slack, Visual Studio Code, etc) display primarily local content (or trusted, secure remote content without Node integration) — if your application executes code from an online source, it is your responsibility to ensure that the code is not malicious.事实上,最流行的Electron应用程序(Atom、Slack、Visual Studio Code等)主要显示本地内容(或不集成节点的可信、安全的远程内容)-如果您的应用程序执行来自在线源的代码,则您有责任确保代码不是恶意的。
General guidelines一般准则
Security is everyone's responsibility安全是每个人的责任
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. 重要的是要记住,Electron应用程序的安全性是框架基础(Chromium、Node.js)、Electron本身、所有NPM依赖项和代码的整体安全性的结果。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.使您的应用程序与最新的Electron框架版本保持最新。When releasing your product, you’re also shipping a bundle composed of Electron, Chromium shared library and Node.js.在发布产品时,您还将交付由Electron、Chromium共享库和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.(如节点集成旁路)已修补,无法在应用程序中利用。For more information, see "Use a current version of Electron".有关更多信息,请参阅“使用当前版本的Electron”。 -
Evaluate your dependencies.评估您的依赖关系。While NPM provides half a million reusable packages, it is your responsibility to choose trusted 3rd-party libraries.虽然NPM提供了50万个可重用包,但您有责任选择受信任的第三方库。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.常见的web漏洞,如跨站点脚本(XSS),对Electron应用程序具有更高的安全影响,因此强烈建议采用安全软件开发最佳实践并执行安全测试。
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. 例如,考虑在默认BrowserWindow中显示远程网站。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.如果攻击者以某种方式设法更改所述内容(通过直接攻击源,或通过位于应用程序和实际目标之间),他们将能够在用户的机器上执行本机代码。
Under no circumstances should you load and execute remote code with Node.js integration enabled. 在任何情况下,都不应在启用Node.js集成的情况下加载和执行远程代码。Instead, use only local files (packaged together with your application) to execute Node.js code. 相反,只使用本地文件(与应用程序一起打包)来执行Node.js代码。To display remote content, use the <webview> tag or BrowserView, make sure to disable the 要显示远程内容,请使用<webview>标记或BrowserView,确保禁用nodeIntegration
and enable contextIsolation
.nodeIntegration
并启用contextIsolation
。
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.它们仅在二进制文件名为Electron时显示,表明开发人员当前正在查看控制台。
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.process.env
或window
对象上设置ELECTRON_ENABLE_SECURITY_WARNINGS
或ELECTRON_DISABLE_SECURITY_WARNINGS
来强制启用或强制禁用这些警告。
Checklist: Security recommendations清单:安全建议
You should at least follow these steps to improve the security of your application:您至少应该遵循以下步骤来提高应用程序的安全性:
Only load secure content仅加载安全内容Disable the Node.js integration in all renderers that display remote content在显示远程内容的所有渲染器中禁用Node.js集成Enable context isolation in all renderers在所有渲染器中启用上下文隔离Enable process sandboxing启用进程沙箱Use在加载远程内容的所有会话中使用ses.setPermissionRequestHandler()
in all sessions that load remote contentses.setPermissionRequestHandler()
Do not disable不要禁用webSecurity
Define a定义Content-Security-Policy
and use restrictive rules (i.e.并使用限制性规则(即script-src 'self'
)script-src 'self'
)Do not enable不要启用allowRunningInsecureContent
- D
o not enable experimental featureso不启用实验功能 Do not use不要使用enableBlinkFeatures
- <webview>
: Do not use:不要使用allowpopups
<webview>
: Verify options and params:验证选项和参数Disable or limit navigation禁用或限制导航Disable or limit creation of new windows禁用或限制创建新窗口Do not use不要将shell.openExternal
with untrusted contentshell.openExternal
用于不受信任的内容Use a current version of Electron使用当前版本的Electron
To automate the detection of misconfigurations and insecure patterns, it is possible to use Electronegativity. 为了自动检测错误配置和不安全模式,可以使用电负性。For additional details on potential weaknesses and implementation bugs when developing applications using Electron, please refer to this guide for developers and auditors.有关使用Electron开发应用程序时潜在弱点和实现错误的更多详细信息,请参阅本开发人员和审计员指南。
1. Only load secure content仅加载安全内容
Any resources not included with your application should be loaded using a secure protocol like 应用程序中未包含的任何资源都应使用安全协议(如HTTPS
. HTTPS
)加载。In other words, do not use insecure protocols like 换句话说,不要使用不安全的协议,如HTTP
. HTTP
。Similarly, we recommend the use of 类似地,我们建议使用WSS
over WS
, FTPS
over FTP
, and so on.WSS
而不是WS
、使用FTPS
而不是FTP
等。
Why?为什么?
HTTPS
has three main benefits:它有三个主要好处:
It authenticates the remote server, ensuring your app connects to the correct host instead of an impersonator.它对远程服务器进行身份验证,确保您的应用程序连接到正确的主机,而不是模拟程序。It ensures data integrity, asserting that the data was not modified while in transit between your application and the host.它确保数据完整性,断言数据在应用程序和主机之间传输时未被修改。It encrypts the traffic between your user and the destination host, making it more difficult to eavesdrop on the information sent between your app and the host.它对用户和目标主机之间的通信进行加密,使得更难窃听应用程序和主机之间发送的信息。
How?怎么做?
// Bad
browserWindow.loadURL('http://example.com')
// Good
browserWindow.loadURL('https://example.com')
<!-- Bad -->
<script crossorigin src="http://example.com/react.js"></script>
<link rel="stylesheet" href="http://example.com/style.css">
<!-- Good -->
<script crossorigin src="https://example.com/react.js"></script>
<link rel="stylesheet" href="https://example.com/style.css">
2. Do not enable Node.js integration for remote content不为远程内容启用Node.js集成
This recommendation is the default behavior in Electron since 5.0.0.该建议是自5.0.0以来Electron的默认行为。
It is paramount that you do not enable Node.js integration in any renderer (BrowserWindow, BrowserView, or <webview>) that loads remote content. 最重要的是,不要在加载远程内容的任何渲染器(BrowserWindow、BrowserView或<webview>)中启用Node.js集成。The goal 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.目标是限制您授予远程内容的权限,从而使攻击者更难在您的网站上执行JavaScript时伤害您的用户。
After this, you can grant additional permissions for specific hosts. 之后,您可以为特定主机授予其他权限。For example, if you are opening a BrowserWindow pointed at 例如,如果打开指向的浏览器窗口https://example.com/
, you can give that website exactly the abilities it needs, but no more.https://example.com/
,您可以为该网站提供所需的功能,但仅此而已。
Why?为什么?
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. 如果攻击者可以跳出渲染器进程并在用户计算机上执行代码,则跨站点脚本(XSS)攻击更危险。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.跨站点脚本攻击相当常见-虽然是一个问题,但它们的能力通常仅限于干扰执行它们的网站。禁用Node.js集成有助于防止XSS升级为所谓的“远程代码执行”(RCE)攻击。
How?怎么做?
// Bad
const mainWindow = new BrowserWindow({
webPreferences: {
contextIsolation: false,
nodeIntegration: true,
nodeIntegrationInWorker: true
}
})
mainWindow.loadURL('https://example.com')
// Good
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(app.getAppPath(), 'preload.js')
}
})
mainWindow.loadURL('https://example.com')
<!-- Bad -->
<webview nodeIntegration src="page.html"></webview>
<!-- Good -->
<webview src="page.html"></webview>
When disabling Node.js integration, you can still expose APIs to your website that do consume Node.js modules or features. 禁用Node.js集成时,您仍然可以向您的网站公开使用Node.js模块或功能的API。Preload scripts continue to have access to 预加载脚本继续访问require
and other Node.js features, allowing developers to expose a custom API to remotely loaded content via the contextBridge API.require
和其他Node.js功能,允许开发人员通过contextBridge API向远程加载的内容公开自定义API。
3. Enable Context Isolation启用上下文隔离
This recommendation is the default behavior in Electron since 12.0.0.该建议是自12.0.0以来Electron的默认行为。
Context isolation is an Electron feature that allows developers to run code in preload scripts and in Electron APIs in a dedicated JavaScript context. 上下文隔离是一种Electron功能,允许开发人员在专用JavaScript上下文中以预加载脚本和ElectronAPI运行代码。In practice, that means that global objects like 实际上,这意味着Array.prototype.push
or JSON.parse
cannot be modified by scripts running in the renderer process.Array.prototype.push
或JSON.parse
等全局对象不能由渲染器进程中运行的脚本修改。
Electron uses the same technology as Chromium's Content Scripts to enable this behavior.Electron使用与Chromium的内容脚本相同的技术来实现这种行为。
Even when 即使使用nodeIntegration: false
is used, to truly enforce strong isolation and prevent the use of Node primitives contextIsolation
must also be used.nodeIntegration:false
,为了真正实施强隔离并防止使用节点原语,也必须使用contextIsolation
。
For more information on what 有关什么是contextIsolation
is and how to enable it please see our dedicated Context Isolation document.contextIsolation
以及如何启用它的更多信息,请参阅专用上下文隔离文档。
4. Enable process sandboxing启用进程沙箱
Sandboxing沙盒 is a Chromium feature that uses the operating system to significantly limit what renderer processes have access to. 是一个Chrome功能,它使用操作系统来显著限制渲染器进程可以访问的内容。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.不建议在未打包的进程(包括主进程)中加载、读取或处理任何不受信任的内容。
For more information on what 有关什么是contextIsolation
is and how to enable it please see our dedicated Process Sandboxing document.contextIsolation
以及如何启用它的更多信息,请参阅专用流程沙箱文档。
5. Handle session permission requests from remote content处理来自远程内容的会话权限请求
You may have seen permission requests while using Chrome: they pop up whenever the website attempts to use a feature that the user has to manually approve (like notifications).您可能在使用Chrome时看到过权限请求:每当网站尝试使用用户必须手动批准的功能(如通知)时,它们就会弹出。
The API is based on the Chromium permissions API and implements the same types of permissions.该API基于Chromium权限API,并实现相同类型的权限。
Why?为什么?
By default, Electron will automatically approve all permission requests unless the developer has manually configured a custom handler. 默认情况下,除非开发人员手动配置了自定义处理程序,否则Electron将自动批准所有权限请求。While a solid default, security-conscious developers might want to assume the very opposite.虽然这是一个可靠的默认值,但有安全意识的开发人员可能希望采取相反的假设。
How?怎么做?
const { session } = require('electron')
const URL = require('url').URL
session
.fromPartition('some-partition')
.setPermissionRequestHandler((webContents, permission, callback) => {
const parsedUrl = new URL(webContents.getURL())
if (permission === 'notifications') {
// Approves the permissions request
callback(true)
}
// Verify URL
if (parsedUrl.protocol !== 'https:' || parsedUrl.host !== 'example.com') {
// Denies the permissions request
return callback(false)
}
})
6. Do not disable 不要禁用webSecurity
This recommendation is Electron's default.此建议是Electron的默认值。
You may have already guessed that disabling the 您可能已经猜到,禁用渲染器进程(BrowserWindow、BrowserView或<webview>)上的webSecurity
property on a renderer process (BrowserWindow, BrowserView, or <webview>) disables crucial security features.webSecurity
属性会禁用重要的安全功能。
Do not disable 不要在生产应用程序中禁用webSecurity
in production applications.webSecurity
。
Why?为什么?
Disabling 禁用webSecurity
will disable the same-origin policy and set allowRunningInsecureContent
property to true
. webSecurity
将禁用同源策略,并将allowRunningInsecureContent
属性设置为true
。In other words, it allows the execution of insecure code from different domains.换句话说,它允许执行来自不同域的不安全代码。
How?怎么做?
// Bad
const mainWindow = new BrowserWindow({
webPreferences: {
webSecurity: false
}
})
// Good
const mainWindow = new BrowserWindow()
<!-- Bad -->
<webview disablewebsecurity src="page.html"></webview>
<!-- Good -->
<webview src="page.html"></webview>
7. Define a Content Security Policy定义内容安全策略
A Content Security Policy (CSP) is an additional layer of protection against cross-site-scripting attacks and data injection attacks. 内容安全策略(CSP)是针对跨站点脚本攻击和数据注入攻击的附加保护层。We recommend that they be enabled by any website you load inside Electron.我们建议您在Electron内部加载的任何网站都启用它们。
Why?为什么?
CSP allows the server serving content to restrict and control the resources Electron can load for that given web page. CSP允许服务内容的服务器限制和控制Electron可以为给定网页加载的资源。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. https://evil.attacker.com
加载的脚本不应允许运行。Defining a CSP is an easy way to improve your application's security.定义CSP是提高应用程序安全性的简单方法。
How?怎么做?
The following CSP will allow Electron to execute scripts from the current website and from 以下CSP将允许Electron从当前网站和apis.example.com
.apis.example.com
执行脚本。
// Bad
Content-Security-Policy: '*'
// Good
Content-Security-Policy: script-src 'self' https://apis.example.com
CSP HTTP headers
Electron respects the Content-Security-Policy HTTPElectron遵守可使用Electron的 header标头 which can be set using Electron's webRequest.onHeadersReceived
handler:webRequest.onHeadersReceived
处理程序设置的Content-Security-Policy
HTTP标头:
const { session } = require('electron')
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
callback({
responseHeaders: {
...details.responseHeaders,
'Content-Security-Policy': ['default-src \'none\'']
}
})
})
CSP meta tag元标签
CSP's preferred delivery mechanism is an HTTP header. CSP的首选传递机制是HTTP头。However, it is not possible to use this method when loading a resource using the 但是,当使用file://
protocol. file://
协议加载资源时,不可能使用此方法。It can be useful in some cases to set a policy on a page directly in the markup using a 在某些情况下,使用<meta>
tag:<meta>
标记直接在标记中的页面上设置策略非常有用:
<meta http-equiv="Content-Security-Policy" content="default-src 'none'">
8. Do not enable 不要启用allowRunningInsecureContent
This recommendation is Electron's default.此建议是Electron的默认值。
By default, Electron will not allow websites loaded over 默认情况下,Electron不允许通过HTTPS
to load and execute scripts, CSS, or plugins from insecure sources (HTTP
). HTTPS
加载的网站加载和执行来自不安全源(HTTP
)的脚本、CSS或插件。Setting the property 将属性allowRunningInsecureContent
to true
disables that protection.allowRunningInsecureContent
设置为true
将禁用该保护。
Loading the initial HTML of a website over 通过HTTPS
and attempting to load subsequent resources via HTTP
is also known as "mixed content".HTTPS
加载网站的初始HTML并尝试通过HTTP
加载后续资源也被称为“混合内容”。
Why?为什么?
Loading content over 通过HTTPS
assures the authenticity and integrity of the loaded resources while encrypting the traffic itself. HTTPS
加载内容可确保加载资源的真实性和完整性,同时对流量本身进行加密。See the section on only displaying secure content for more details.有关详细信息,请参阅仅显示安全内容一节。
How?怎么做?
// Bad
const mainWindow = new BrowserWindow({
webPreferences: {
allowRunningInsecureContent: true
}
})
// Good
const mainWindow = new BrowserWindow({})
9. Do not enable experimental features不要启用实验功能
This recommendation is Electron's default.此建议是Electron的默认值。
Advanced users of Electron can enable experimental Chromium features using the Electron的高级用户可以使用experimentalFeatures
property.experimentalFeatures
属性启用实验铬功能。
Why?为什么?
Experimental features are, as the name suggests, experimental and have not been enabled for all Chromium users. 顾名思义,实验性功能是实验性的,尚未为所有Chrome用户启用。Furthermore, their impact on Electron as a whole has likely not been tested.此外,它们对整个Electron的影响可能还没有得到测试。
Legitimate use cases exist, but unless you know what you are doing, you should not enable this property.存在合法的用例,但除非您知道自己在做什么,否则不应启用此属性。
How?怎么做?
// Bad
const mainWindow = new BrowserWindow({
webPreferences: {
experimentalFeatures: true
}
})
// Good
const mainWindow = new BrowserWindow({})
10. Do not use 不要使用enableBlinkFeatures
This recommendation is Electron's default.此建议是Electron的默认值。
Blink is the name of the rendering engine behind Chromium. Blink是Chromium背后的渲染引擎的名称。As with 与experimentalFeatures
, the enableBlinkFeatures
property allows developers to enable features that have been disabled by default.experimentalFeatures
一样,enableBlinkFeatures
属性允许开发人员启用默认禁用的功能。
Why?为什么?
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.在任何情况下都不应推测性地启用功能。
How?怎么做?
// Bad
const mainWindow = new BrowserWindow({
webPreferences: {
enableBlinkFeatures: 'ExecCommandInJavaScript'
}
})
// Good
const mainWindow = new BrowserWindow()
11. Do not use allowpopups
for WebViews不要对Web视图使用allowpopups
allowpopups
for WebViewsThis recommendation is Electron's default.此建议是Electron的默认值。
If you are using <webview>, you might need the pages and scripts loaded in your 如果您使用的是<webview>,则可能需要在<webview>
tag to open new windows. <webview>
标记中加载页面和脚本以打开新窗口。The allowpopups
attribute enables them to create new BrowserWindows using the window.open()
method. allowpopups
属性使他们能够使用window.open()
方法创建新的BrowserWindows。<webview>
tags are otherwise not allowed to create new windows.否则不允许标记创建新窗口。
Why?为什么?
If you do not need popups, you are better off not allowing the creation of new BrowserWindows by default. 如果您不需要弹出窗口,最好不要在默认情况下创建新的BrowserWindows。This follows the principle of minimally required access: Don't let a website create new popups unless you know it needs that feature.这遵循了最低访问要求的原则:不要让网站创建新的弹出窗口,除非您知道它需要该功能。
How?怎么做?
<!-- Bad -->
<webview allowpopups src="page.html"></webview>
<!-- Good -->
<webview src="page.html"></webview>
12. Verify WebView options before creation在创建之前验证WebView选项
A WebView created in a renderer process that does not have Node.js integration enabled will not be able to enable integration itself. 在未启用Node.js集成的渲染器进程中创建的Web视图本身将无法启用集成。However, a WebView will always create an independent renderer process with its own 但是,WebView总是使用自己的webPreferences
.webPreferences
创建独立的渲染器进程。
It is a good idea to control the creation of new <webview> tags from the main process and to verify that their webPreferences do not disable security features.最好控制从主进程创建新的<webview>标记,并验证其webPreferences未禁用安全功能。
Why?为什么?
Since 由于<webview>
live in the DOM, they can be created by a script running on your website even if Node.js integration is otherwise disabled.<webview>
位于DOM中,因此即使Node.js集成被禁用,也可以通过在您的网站上运行的脚本创建它们。
Electron enables developers to disable various security features that control a renderer process. Electron使开发人员能够禁用控制渲染器进程的各种安全功能。In most cases, developers do not need to disable any of those features - and you should therefore not allow different configurations for newly created <webview> tags.在大多数情况下,开发人员不需要禁用这些功能中的任何一项,因此不应允许对新创建的<webview>标签进行不同的配置。
How?怎么做?
Before a <webview> tag is attached, Electron will fire the 在附加<webview>标记之前,Electron将在托管的will-attach-webview
event on the hosting webContents
. WebContents
上触发will-attach-webview
事件。Use the event to prevent the creation of 使用此事件可防止创建具有可能不安全选项的webViews
with possibly insecure options.webViews
。
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
// Disable Node.js integration
webPreferences.nodeIntegration = false
// Verify URL being loaded
if (!params.src.startsWith('https://example.com/')) {
event.preventDefault()
}
})
})
Again, this list merely minimizes the risk, but does not remove it. If your goal is to display a website, a browser will be a more secure option.同样,这个列表只是将风险最小化,但并没有消除风险。如果您的目标是显示网站,浏览器将是一个更安全的选择。
13. Disable or limit navigation禁用或限制导航
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.如果您的应用程序不需要导航或只需要导航到已知页面,最好将导航完全限制在已知范围内,不允许任何其他类型的导航。
Why?为什么?
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. 如果攻击者能够说服您的应用程序离开当前页面,他们可能会迫使您的应用打开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.webContents
被配置为更安全(如禁用nodeIntegration
或启用contextIsolation
),让您的应用程序打开一个随机网站也会使利用应用程序的工作更容易。
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.这通常通过链接、插件或其他用户生成的内容完成。
How?怎么做?
If your app has no need for navigation, you can call 如果您的应用程序不需要导航,则可以在event.preventDefault()
in a will-navigate handler. will-navigate
处理程序中调用event.preventDefault()
。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.如果您知道应用程序可能导航到哪些页面,请检查事件处理程序中的URL,并仅在与您期望的URL匹配时才允许导航。
We recommend that you use Node's parser for URLs. 我们建议您使用节点的URL解析器。Simple string comparisons can sometimes be fooled - a 简单的字符串比较有时会被愚弄-startsWith('https://example.com')
test would let https://example.com.attacker.com
through.startsWith('https://example.com')
测试会让https://example.com.attacker.com
通过
const URL = require('url').URL
app.on('web-contents-created', (event, contents) => {
contents.on('will-navigate', (event, navigationUrl) => {
const parsedUrl = new URL(navigationUrl)
if (parsedUrl.origin !== 'https://example.com') {
event.preventDefault()
}
})
})
14. Disable or limit creation of new windows禁用或限制创建新窗口
If you have a known set of windows, it's a good idea to limit the creation of additional windows in your app.如果您有一组已知的窗口,最好限制在应用程序中创建其他窗口。
Why?为什么?
Much like navigation, the creation of new 与导航非常相似,创建新的webContents
is a common attack vector. webContents
是常见的攻击向量。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.BrowserWindow
并且不需要在运行时打开任意数量的其他窗口的应用程序,通常是这样。
How?怎么做?
webContents will delegate to its 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. url
以及用于创建窗口的选项。We recommend that you register a handler to monitor the creation of windows, and deny any unexpected window creation.我们建议您注册一个处理程序来监视窗口的创建,并拒绝任何意外的窗口创建。
const { shell } = require('electron')
app.on('web-contents-created', (event, contents) => {
contents.setWindowOpenHandler(({ url }) => {
// In this example, we'll ask the operating system
// to open this event's url in the default browser.
//
// See the following item for considerations regarding what
// URLs should be allowed through to shell.openExternal.
if (isSafeForExternalOpen(url)) {
setImmediate(() => {
shell.openExternal(url)
})
}
return { action: 'deny' }
})
})
15. Do not use shell.openExternal
with untrusted content不要将shell.openExternal
用于不受信任的内容
shell.openExternal
with untrusted contentThe shell module's openExternal API allows opening a given protocol URI with the desktop's native utilities. shell模块的openExternalAPI允许使用桌面的本机实用程序打开给定的协议URI。On macOS, for instance, this function is similar to the 例如,在macOS上,该函数类似于open
terminal command utility and will open the specific application based on the URI and filetype association.open
终端命令实用程序,将根据URI和文件类型关联打开特定应用程序。
Why?为什么?
Improper use of openExternal can be leveraged to compromise the user's host. 不正确使用openExternal可能会危害用户的主机。When openExternal is used with untrusted content, it can be leveraged to execute arbitrary commands.当openExternal用于不受信任的内容时,可以利用它执行任意命令。
How?怎么做?
// Bad
const { shell } = require('electron')
shell.openExternal(USER_CONTROLLED_DATA_HERE)
// Good
const { shell } = require('electron')
shell.openExternal('https://example.com/index.html')
16. Use a current version of Electron使用当前版本的Electron
You should strive for always using the latest available version of Electron. 您应该努力始终使用最新版本的Electron。Whenever a new major version is released, you should attempt to update your app as quickly as possible.无论何时发布新的主要版本,您都应尝试尽快更新应用程序。
Why?为什么?
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. 使用旧版本的Electron、Chromium和Node.js构建的应用程序比使用这些组件的最新版本的应用程序更容易成为目标。Generally speaking, security issues and exploits for older versions of Chromium and Node.js are more widely available.一般来说,Chromium和Node.js的旧版本的安全问题和漏洞利用更为广泛。
Both Chromium and Node.js are impressive feats of engineering built by thousands of talented developers. Chromium和Node.js都是由数千名有才华的开发人员打造的令人印象深刻的工程壮举。Given their popularity, their security is carefully tested and analyzed by equally skilled security researchers. 考虑到它们的流行性,它们的安全性由同样熟练的安全研究人员仔细测试和分析。Many of those researchers disclose vulnerabilities responsibly, which generally means that researchers will give Chromium and Node.js some time to fix issues before publishing them. 这些研究人员中的许多人负责地披露了漏洞,这通常意味着研究人员在发布之前会给Chromium和Node.js一些时间来解决问题。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.如果您的应用程序运行的是最新版本的Electron(因此,Chromium和Node.js),其潜在的安全问题并不广为人知,那么它将更加安全。
How?怎么做?
Migrate your app one major version at a time, while referring to Electron's Breaking Changes document to see if any code needs to be updated.每次迁移一个主要版本的应用程序,同时参考Electron的突破性更改文档,查看是否需要更新任何代码。
17. Validate the sender
of all IPC messages验证所有IPC消息的sender
sender
of all IPC messagesYou should always validate incoming IPC messages 您应该始终验证传入IPC消息sender
property to ensure you aren't performing actions or sending information to untrusted renderers.sender
属性,以确保您没有执行操作或向不受信任的呈现器发送信息。
Why?为什么?
All Web Frames can in theory send IPC messages to the main process, including iframes and child windows in some scenarios. 理论上,所有Web框架都可以向主进程发送IPC消息,在某些情况下包括IFrame和子窗口。If you have an IPC message that returns user data to the sender via 如果您有一条IPC消息,通过event.reply
or performs privileged actions that the renderer can't natively, you should ensure you aren't listening to third party web frames.event.reply
将用户数据返回给发送者,或者执行渲染器本机无法执行的特权操作,则应确保您没有监听第三方web框架。
You should be validating the 默认情况下,您应该验证所有IPC消息的sender
of all IPC messages by default.sender
。
How?怎么做?
// Bad
ipcMain.handle('get-secrets', () => {
return getSecrets();
});
// Good
ipcMain.handle('get-secrets', (e) => {
if (!validateSender(e.senderFrame)) return null;
return getSecrets();
});
function validateSender(frame) {
// Value the host of the URL using an actual URL parser and an allowlist
if ((new URL(frame.url)).host === 'electronjs.org') return true;
return false;
}