Segurança
A superfície de ataque de um navegador divide-se em duas: o motor, que não fomos nós a escrever, e o invólucro, que foi. Comportam-se de maneira muito diferente, por isso descrevemo-los em separado. As lacunas conhecidas desta versão estão no fim da página.
O motor: Chromium, V8, Skia
Ao longo de 2026 foram corrigidas no Chrome dezenas de falhas de segurança de memória, seis delas zero-day já explorados em ataques reais. Não somos nós a escrever este código e não o podemos corrigir; aqui a única defesa é manter o motor atualizado.
Por isso a nossa regra é clara: o Girginos Browser não é lançado sobre uma versão do Electron em fim de vida. O Electron só suporta as suas três últimas versões principais e a fixação da versão é verificada antes de cada lançamento. De momento usamos o Electron 44.2.0 com o Chromium 152.0.7977.76.
O invólucro: o código que escrevemos
Estas são as decisões de arquitetura do lado do invólucro:
- Cada separador é uma WebContentsView independente. O conteúdo das páginas corre com sandbox: true, contextIsolation: true e nodeIntegration: false, e não recebe qualquer preload.
- A janela da interface também corre em sandbox e partilha a sessão com os separadores, pelo que os seus próprios pedidos passam igualmente pelo bloqueador e levam os cabeçalhos DNT.
- Os canais IPC só são aceites a partir da frame principal da janela da interface. As escritas de definições passam por validação de chave e de tipo.
- As transferências são endereçadas por identificador; um caminho de ficheiro em bruto vindo da interface nunca é aberto.
- As navegações iniciadas pela página só podem ser http(s) e view-source:http(s). file: e chrome: só abrem se for o utilizador a escrevê-los na barra de endereço.
- A passagem para uma aplicação externa está limitada a uma lista restrita de esquemas: mailto:, tel:, sms:, magnet:, ftp(s):, webcal:. Só pode estar aberta uma caixa de confirmação de cada vez.
- As origens opacas — aquelas cuja origin é null, como data: e about: — são sempre recusadas nos pedidos de permissão.
- A verificação ortográfica está desligada, porque o Chromium transfere os ficheiros de dicionário de um servidor da Google.
- Os dados são escritos de forma atómica, através de um ficheiro temporário e de uma mudança de nome.
Vetores de ataque e contramedidas
| Classe | Exemplo | Contramedida |
|---|---|---|
| Falsificação da barra de endereço | RLO/bidi, CR-LF, NUL, bank.com@evil.com, enchimento com espaços, homógrafos IDN | Os caracteres invisíveis e os espaços ficam codificados em percentagem, as credenciais são ocultadas e o punycode é mostrado |
| Ocultação do domínio | accounts.google.com.giris.evil.com | O domínio registável fica a cor cheia e o resto esbatido |
| Imitação de páginas internas | newtab.html, uma cópia transferida | O endereço tem de corresponder por inteiro; não se faz procura por subcadeia |
| Falsificação da interface em ecrã inteiro | uma página passa a ecrã inteiro e desenha uma barra de ferramentas falsa | A vista da página nunca é ampliada por cima do invólucro |
| Fuga de esquema | file:, chrome:, blob:, view-source:file: | Nas navegações iniciadas pela página, apenas http(s) |
| Invocação de aplicação externa | ms-msdt:, search-ms:, ms-appinstaller: | Lista restrita de permissões e uma única caixa de confirmação |
| Truques no nome da transferência | evil.exe / evil.exe., ponto ou espaço no fim, extensão ocultada com RLO | Normalização antes da verificação da extensão; a decisão segue o nome real em disco |
| Evasão ao bloqueador | izleyici.com., ponto no fim | Normalização do host |
A cadeia de atualização assinada
O modelo de ameaça parte do princípio de que o servidor de atualizações pode já estar comprometido. A sequência decorre assim:
- São obtidos o manifesto assinado e o ficheiro de assinatura que o acompanha.
- A assinatura é verificada sobre os bytes em bruto do manifesto, com a chave pública Ed25519 incorporada na aplicação. Se não passar, não é lido um único campo.
- São aplicadas as barreiras de versão: a descida para uma versão anterior é recusada; um manifesto para além da sua própria data de validade é recusado — isto defende contra o ataque que serve indefinidamente um manifesto antigo para congelar as atualizações; onde for necessário, exige-se uma versão intermédia; e o endereço de transferência tem de ser https.
- A versão e o hash do pacote encontrados pelo transferidor têm de coincidir exatamente com os do manifesto assinado.
- Terminada a transferência, o hash sha512 do pacote é comparado em tempo constante com o hash assinado.
- A instalação só começa depois da confirmação do utilizador.
Se algum dos passos falhar, não há atualização. A chave privada nunca fica no servidor; mesmo que o servidor fosse tomado, um atacante não conseguiria produzir um manifesto válido.
Testes
Correm sobre o código 118 testes unitários, 73 regressões de vetores de ataque e 46 testes de verificação de atualizações; o contrato IPC e DOM entre a interface e o processo principal é testado à parte. Além destes, antes e depois de cada lançamento correm scripts de verificação ponta a ponta sobre os resultados reais e sobre o servidor em produção.
Lacunas conhecidas
O que se segue falta na 0.1.0. Escondê-lo faria o produto parecer mais seguro do que é, por isso dizemo-lo abertamente.
- Sem Mark-of-the-Web
- Não é escrito qualquer Zone.Identifier nos ficheiros transferidos, pelo que o Windows SmartScreen não entra em ação para eles. O navegador mostra o seu próprio aviso, mas falta a camada do sistema operativo.
- Sem certificado de assinatura de código
- A assinatura de código do pacote de instalação não pode ser verificada. O manifesto assinado resolve isto para as atualizações, mas a primeira instalação fica exposta.
- Sem Public Suffix List
- Em domínios de alojamento como github.io, as exceções por site e o destaque na barra de endereço abrangem mais do que deveriam.
- Os erros de certificado usam a predefinição do Chromium
- Não foi escrito um ecrã «continuar mesmo assim» próprio; com um certificado inválido a página simplesmente não abre.
- O bloqueio é apenas ao nível do domínio
- Os rastreadores escondidos atrás de registos CNAME e a publicidade servida a partir da primeira parte não são apanhados, e não é aplicado qualquer filtro cosmético.