Segurança
Para obter informações sobre como divulgar adequadamente uma vulnerabilidade do Electron, consulte SECURITY.md.
Para vulnerabilidades no Chromium upstream: O Electron mantém-se atualizado com lançamentos alternados do Chromium. Para obter mais informações, consulte o documento Cronogramas de Lançamento do Electron.
Prefácio
Como desenvolvedores da web, nós comumente aproveitamos da forte rede de segurança do navegador — os riscos associados com o código que escrevemos são relativamente pequenos. Nossos sites tem poderes limitados em uma caixa de areia e confiamos que nossos usuários desfrutam de num navegador construído por uma grande equipe de engenheiros os quais são capazes de responder rapidamente às ameaças de segurança recém-descobertas.
Ao trabalhar com Electron, é importante entender que Electron não é um navegador web. Isto permite que você construa aplicações desktop ricas com tecnologias web familiar, mas seu código exerce um poder muito maior. JavaScript pode acessar o sistema de arquivos, o shell do usuário e muito mais. Isto permite que você crie aplicativos nativos de alta qualidade, mas os riscos de segurança inerentes escalam com os poderes adicionais concedidos ao seu código.
Com isso em mente, esteja ciente de que exibir conteúdo arbitrário de fontes não confiáveis representa um grave risco de segurança que o Electron não pretende manipular. De fato, os mais populares aplicativos Electron (Atom, Slack, Visual Studio Code, etc.) mostram, primeiramente, conteúdo local (ou confiável, ou que é seguro e remoto, sem alguma interação com Node) — se a sua aplicação executa código de uma fonte online, é sua responsabilidade garantir que o código não seja malicioso.
Diretrizes gerais
Segurança é da responsabilidade de todos
É importante lembrar que a segurança do seu aplicativo Electron é o resultado da segurança geral da fundação do framework (Chromium, Node.js), o Electron em si, todas as dependências NPM e também seu código. Portanto, é sua responsabilidade seguir algumas das importantes boas práticas:
-
Mantenha sua aplicação atualizada com a última versão do framework Electron. Ao lançar seu produto, você também está enviando um pacote composto pelo Electron, Biblioteca Compartilhada do Chromium e Node.js. Vulnerabilidades afetando estes componentes podem afetar a segurança do seu aplicativo. Ao atualizar o Electron para a versão mais recente, você garante que as vulnerabilidades críticas (como nodeIntegration bypasses) já estão corrigidas e não podem ser exploradas em seu aplicativo. Para obter mais informações, consulte "Use uma versão atual do Electron".
-
Avalie suas dependências. O NPM fornece meio milhão de pacotes reutilizáveis, mas é sua responsabilidade escolher bibliotecas de terceiros confiáveis. Se você usar bibliotecas desatualizadas afetadas por vulnerabilidades conhecidas ou se depender de código mal mantido, a segurança do aplicativo pode estar comprometida.
-
Adote práticas seguras de codificação. A primeira linha de defesa para seu aplicativo é seu próprio código. Vulnerabilidades comuns na web, como "Cross-Site Scripting" (XSS), têm um impacto maior na segurança de aplicações Electron, portanto é altamente recomendado adotar as melhores práticas de desenvolvimento de software seguro e realizar testes de segurança.
Isolamento para conteúdo não confiável
Existe um problema de segurança sempre que você recebe código de uma fonte não confiável (por exemplo, de um servidor remoto) e o executa localmente. Por exemplo, considere um site remoto sendo exibido dentro de uma BrowserWindow
padrão. Se um invasor de alguma forma conseguir alterar esse conteúdo (seja atacando diretamente a fonte ou ficando entre o seu aplicativo e o destino real), ele poderá executar código nativo na máquina do usuário.
Em nenhuma circunstância você deve carregar e executar código remoto com a integração Node.js habilitada. Em vez disso, use apenas arquivos locais (empacotados junto com o seu aplicativo) para executar código Node.js. To display remote content, use the <webview>
tag or a WebContentsView
and make sure to disable the nodeIntegration
and enable 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.
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.
Checklist: Security recommendations
You should at least follow these steps to improve the security of your application:
- Apenas carregar conteúdo seguro
- Desativar a integração do Node.js em todos os renderizadores que exibem conteúdo remoto
- Ativar isolamento de contexto em todos os renderizadores
- Enable process sandboxing
- Use
ses.setPermissionRequestHandler()
in all sessions that load remote content - Do not disable
webSecurity
- Define a
Content-Security-Policy
and use restrictive rules (i.e.script-src 'self'
) - Do not enable
allowRunningInsecureContent
- Do not enable experimental features
- Do not use
enableBlinkFeatures
<webview>
: Do not useallowpopups
<webview>
: Verify options and params- Disable or limit navigation
- Disable or limit creation of new windows
- Do not use
shell.openExternal
with untrusted content - Use uma versão atual do Electron
- Validate the
sender
of all IPC messages - Avoid usage of the
file://
protocol and prefer usage of custom protocols - Check which fuses you can change
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.
1. Apenas carregar conteúdo seguro
Any resources not included with your application should be loaded using a secure protocol like HTTPS
. In other words, do not use insecure protocols like HTTP
. Similarly, we recommend the use of WSS
over WS
, FTPS
over FTP
, and so on.
Por que?
HTTPS
has two main benefits:
- 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.
Como?
// 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
This recommendation is the default behavior in Electron since 5.0.0.
It is paramount that you do not enable Node.js integration in any renderer (BrowserWindow
, WebContentsView
, or <webview>
) that loads remote content. 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.
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.
Por que?
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. 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.
Como?
// 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>