Um navegador remoto ingênuo compartilha um único processo de navegador entre muitos usuários. Cookies definidos em uma sessão aparecem na seguinte; dados de localStorage atravessam os limites da sessão; o estado de autenticação de um usuário pode ser assumido por outro. Mesmo que a própria aplicação protegida se comporte bem, o navegador compartilhado torna-se um canal lateral que contorna todo controle de acesso de nível de aplicação.
Há também a navegação. Um usuário com permissão apenas de visualização de um único painel interno clica em um link de phishing dentro desse painel, abre uma nova aba para uma conta pessoal ou segue um link externo que não pretendia. Sem imposição na camada de navegador, a sessão escapa da aplicação protegida — e agora o ID de sessão da aplicação protegida, a identidade do usuário e o estado de navegação ativo tornam-se visíveis no lugar para onde o navegador foi.
O isolamento de contexto de navegador fecha ambos. Cada sessão roda em seu próprio contexto de navegador sem estado compartilhado. O próprio navegador impõe uma lista de domínios permitidos que a sessão pode alcançar e bloqueia todo canal que o usuário poderia usar para ir a outro lugar — novas abas, pop-ups, cliques em links para domínios não permitidos, navegação programática pela própria página.
Cada sessão recebe seu próprio contexto de navegador dentro do motor de renderização — totalmente separado do estado de toda outra sessão. Uma lista de domínios permitidos rigorosa detém na camada de navegação — interceptação de solicitações, polling de navegação de aplicações de página única e interceptação de cliques em links garantem juntos que a sessão nunca alcance um domínio não permitido. Por baixo, os próprios pixels renderizados carregam modificações contínuas de baixo nível que quebram as ferramentas de automação que tentam ler ou interagir com a sessão.
Cada sessão de usuário abre em seu próprio contexto de navegador isolado — um perfil novo com seu próprio pote de cookies, seu próprio armazenamento local, seu próprio estado de sessão. Dois usuários na mesma aplicação protegida têm navegadores totalmente independentes; nada de uma sessão é visível para a outra. O fim da sessão destrói totalmente o contexto; nenhum estado sobrevive.
Cada tentativa de navegação é capturada antes de ser executada. A camada de solicitações bloqueia domínios não permitidos no nível de rede; os cliques em links dentro da página são capturados na camada de renderização; as navegações de aplicações de página única (pushState, replaceState) são capturadas por polling. A sessão não consegue alcançar um domínio fora da lista de permissões, seja o usuário tentando de propósito, seja a própria página tentando por conta própria.
O navegador em estilo quiosque não permite que o usuário abra nova aba, crie pop-up ou use o menu de contexto do clique com o botão direito. Todo canal que o usuário poderia usar para escapar da aplicação protegida é fechado na configuração do navegador. O usuário trabalha dentro da sessão aberta para ele — nada além disso.
Sob o conteúdo visível, o fluxo de pixels renderizado carrega modificações contínuas de baixo nível — ruído aleatório, deslocamentos de cor sutis, micro deslocamento de elementos, oscilação subpixel. Eles não afetam o que o usuário vê, mas quebram as ferramentas de automação (Selenium, scripts de Puppeteer, raspadores de tela) que tentam ler ou interagir com a sessão por fora do canal de entrada oficial.
Cada comportamento abaixo é configurado por serviço protegido e imposto na camada de navegador, não no código da aplicação protegida. A aplicação protegida não precisa estar ciente de que eles existem — a fronteira é invisível para o tempo de execução da aplicação.
Cada sessão roda em seu próprio contexto de navegador — uma estrutura de nível Chromium que dá à sessão seu próprio pote de cookies, seu próprio armazenamento local, seu próprio registro de service worker, suas próprias permissões, seu próprio estado de sessão. Duas sessões na mesma aplicação protegida não compartilham nada em nível de navegador.
Cada solicitação de navegação — documento principal, subdocumento, fetch, XHR — passa por um interceptador que verifica o domínio de destino contra a lista de permissões da sessão. Domínios não permitidos são bloqueados antes que a conexão seja estabelecida. Não há condição de corrida entre o clique do usuário e a verificação da navegação.
Aplicações de página única modernas navegam chamando pushState ou replaceState sem fazer uma solicitação de rede. Um interceptador de solicitações simples não consegue capturá-las. O ZeroLeak também faz polling da URL atual dentro da página em um intervalo curto, de modo que navegações SPA para caminhos não permitidos são capturadas e revertidas em segundos.
Elementos de link com destino não permitido, chamadas window.open(), mudanças programáticas de localização — tudo é capturado dentro da página renderizada antes de ser executado. O usuário que clica em um link que não pode seguir é bloqueado no momento do clique, não depois que a solicitação de rede já começou.
O navegador está configurado de modo que qualquer tentativa de criar um novo alvo de navegação — pelo usuário, pela página ou por um script — seja capturada e descartada imediatamente. A sessão sempre tem exatamente uma aba visível, e essa é a aba da aplicação protegida.
Cada sessão monitora a interação do usuário. Se o usuário ficar inativo por mais tempo do que o tempo limite configurado, a sessão é encerrada de forma graciosa, o contexto de navegador é destruído e (quando configurado) um webhook informa o coordenador, para que a política de destino possa ser atualizada. Sem navegadores isolados abandonados consumindo memória.
Além do isolamento por sessão e da fronteira de navegação, o próprio fluxo de pixels renderizado carrega modificações contínuas de baixo nível. O objetivo delas é quebrar as ferramentas de automação — os scripts que, do contrário, leriam a tela da sessão, identificariam elementos e interagiriam por canais não oficiais — sem afetar como a página parece ou se comporta para o usuário humano.
Uma camada de canvas desenha continuamente ruído aleatório de baixa intensidade por toda a página renderizada. O olho humano percebe no máximo uma leve textura; os scripts de OCR e de correspondência de modelos que tentam ler a tela perdem as bordas de pixel consistentes em que confiam. A intensidade do ruído e a taxa de atualização são configuráveis por serviço protegido.
Uma camada semitransparente aplica um matiz de cor aleatório que muda lentamente por toda a página renderizada. As áreas brancas e pretas ainda parecem efetivamente brancas e pretas ao olho, mas os valores reais de pixel se deslocam. As ferramentas de automação baseadas em visão que fazem correspondência contra assinaturas de cor perdem suas referências.
Um desfoque contínuo muito leve é aplicado como filtro de tela. Cada quadro é ligeiramente diferente em seu detalhe de alta frequência, o que dificulta que os OCRs e os correspondedores de padrões encontrem pontos de característica estáveis. O usuário não percebe o desfoque à distância normal de leitura.
Os elementos da página são deslocados aleatoriamente de 1 a 3 pixels em relação às suas posições normais. O deslocamento está abaixo da percepção humana, mas quebra os scripts que localizam elementos por coordenadas absolutas de tela. As ferramentas de automação não podem confiar em uma posição fixa de elemento de um quadro para outro.
Em um intervalo curto, toda a superfície renderizada é deslocada em alguns pixels — pequeno o suficiente para não atrapalhar a leitura, grande o suficiente para derrotar as ferramentas de automação que dependem de coordenadas absolutas de pixel consistentes para simulação de entrada. Ataques de replay no estilo Selenium perdem seus pontos fixos.
Interfaces de infraestrutura crítica em que vazamento de estado entre sessões ou navegação indesejada pode afetar sistemas físicos. O isolamento por sessão garante que dois operadores no mesmo console não consigam ver a sessão um do outro; a lista de permissões rigorosa garante que nenhum deles passe do console operacional para um link externo.
Painéis internos, interfaces de auditoria e ferramentas de relatório acessados por muitos usuários — incluindo prestadores e auditores externos. Cada sessão é seu próprio navegador, a política de acesso é imposta na camada de navegação, e as defesas da camada de renderização resistem à automação de qualquer um que tente raspar a tela.
O contexto por sessão significa que um prestador visualizando um data room não consegue ver os cookies, o histórico de busca ou os IDs de sessão de um prestador diferente em um data room diferente. A lista de permissões garante que a sessão do data room nunca vá para a internet mais ampla.
Portais de estudos em que vários pesquisadores acessam dados de pacientes sob limites rigorosos de divulgação. O isolamento por sessão impõe a fronteira na camada de navegador; a lista de permissões impõe na camada de navegação; as defesas de renderização resistem à automação de qualquer um que tente raspar os dados pelo canal de tela.
Vamos rodar duas sessões lado a lado na mesma aplicação protegida, mostrar que nada vaza entre elas, tentar ir para fora da lista de permissões e tentar conduzir a sessão com uma ferramenta de automação externa — e mostrar o que acontece.