
Isolamento e encapsulamento seguros de árvores DOM usando ShadowDOM
⚠️ EXPERIMENTAL [WIP] - USE POR SUA CONTA E RISCO (saiba mais)
Tente quebrar o LavaDome - visite o aplicativo de demonstração, abra o console e faça tudo ao seu alcance para roubar o segredo de dentro da instância do LavaDome (relate seu sucesso)
Nos padrões web atuais, não há uma forma estabelecida de isolar seletivamente subárvores do DOM de maneira segura. Em outras palavras, não podemos controlar o acesso a seções do DOM concedendo acesso a algumas partes enquanto bloqueamos o acesso de outras, se elas compartilharem o mesmo ambiente de execução JavaScript.
Vivemos em um mundo onde não podemos mais confiar no código dos nossos próprios aplicativos, e a execução de mesma origem não garante segurança. Para proteger segredos no frontend, precisamos ser capazes de apresentar conteúdo ao usuário enquanto garantimos que ele não possa ser comprometido por código JavaScript executado sob a mesma origem.

Atualmente, esse conteúdo sensível é simplesmente anexado ao DOM após ser exportado, tornando-o totalmente acessível a todas as entidades que executam no mesmo aplicativo. Ou seja, seções do código que não deveriam ter acesso à chave privada poderiam extraí-la facilmente em texto simples, desde que o código malicioso tenha acesso ao DOM.
Mas fique tranquilo. Acreditamos que este é um problema solucionável 👇
O LavaDome atualmente suporta JavaScript Vanilla e React (com mais a caminho)
import { LavaDome as LavaDomeJavaScript } from '@lavamoat/lavadome-javascript';
const root = document.getElementById('root'); const lavadome = new LavaDomeJavaScript(root); lavadome.text(secret); lavadome.copy(); // copy to clipboard
### [React](https://github.com/lavamoat/lavadome/blob/main/packages/react)```javascript
import { LavaDome as LavaDomeReact, toLavaDomeToken } from '@lavamoat/lavadome-react';
function Secret({ text }) {
const {token, copy} = toLavaDomeCapabilities(text);
return <>
<a onClick={copy}> copy to clipboard </a>
<LavaDomeReact token={token} />
</>;
}
Além do nó raiz, todos os construtores aceitam um 2º argumento opcional de opções:```javascript // javascript new LavaDomeJavaScript(root, { // boolean unsafeOpenModeShadow: false, });
// react function Secret({ text }) { const {token} = toLavaDomeCapabilities(text); return <LavaDomeReact token={token} // boolean unsafeOpenModeShadow={false} /> }
### Uso Seguro
Devido às limitações do núcleo web, para integrar o LavaDome com segurança, há algumas coisas a serem consideradas que exigem algum esforço ativo por parte do desenvolvedor que realiza a integração:
#### Ordem de Execução
O LavaDome, como qualquer outro software de segurança JavaScript, está sempre vulnerável a código que é executado antes dele.
Isso significa que, exceto para código em que confiamos absolutamente, o LavaDome deve ser o primeiro pedaço de código a carregar no programa da aplicação web.
Embora isso não signifique que o desenvolvedor deva usá-lo imediatamente (mas sim apenas quando necessário), ele deve, no entanto, incluir o programa o mais cedo possível.
Para fazer isso corretamente (com segurança), ele deve ser a primeira declaração de import/require em todo o programa:```javascript
import '@lavamoat/lavadome-react';
import 'other-stuff';
console.log('Program starts here');
Dessa forma, garantimos que o LavaDome se prepare para o uso seguro.
Observe que isso se aplica de forma semelhante ao restante dos pacotes do LavaDome e não apenas ao @lavamoat/lavadome-react (portanto, importar mais de um deles é desnecessário).
Vá para Security(defensive-coding) para saber mais.
Devido a ataques de side channel e limitações da web, importar fontes remotas pode ser uma técnica eficaz contra o LavaDome. Como isso está embutido no âmbito do CSS, atualmente não é possível resolver esse problema por meio do LavaDome.
Felizmente, isso pode ser resolvido de forma eficaz usando a diretiva font-src do CSP.
Para mitigar essa forma de ataque, certifique-se de que seu aplicativo web não permita buscar fontes de servidores desconhecidos.
Vá para Security(side-channeling) para saber mais.
O texto fornecido ao LavaDome pelo desenvolvedor deve ser 100% imprevisível; caso contrário, pode ser atacado e vazado.
Portanto, se o seu aplicativo precisar apresentar "your key is 234789", isso significa que sua estrutura DOM deve ser:```html
your key is 234789
e não deve ser:```html
<span> <lavadome>your key is 234789</lavadome> </span>
Vá para Segurança(findability) para saber mais.
Integrar LavaDome pode ser complicado no contexto de testá-lo, porque, como o LavaDome faz um bom trabalho ao esconder o segredo, ele o esconde muito bem dos seus testes também!
Para integrar LavaDome com sucesso no seu ambiente de testes, você pode precisar de alguma ajuda de LavaDomeDebug, que é exportado por @lavamoat/lavadome-core:```javascript
// IMPORT/USE FOR TESTING/DEBUGGING PURPOSES ONLY - NEVER IN PRODUCTION!
import { LavaDomeDebug } from '@lavamoat/lavadome-core';
Aqui estão alguns dos métodos utilitários de depuração que `LavaDomeDebug` exporta e que podem ajudar você a testar componentes baseados em `LavaDome`:
#### `getTextByRoot()`
Dado um root (`raiz`) anexado a um `LavaDome`, `getTextByRoot()` extrairá e reconstruirá recursivamente o segredo interno. Para que isso seja possível, a instância de `LavaDome` deve ser iniciada originalmente com a opção INSEGURA `@unsafeOpenModeShadow`, que torna as sombras internas de `LavaDome` acessíveis a partir de fora.
Naturalmente, isso é INSEGURO e deixa `LavaDome` totalmente vulnerável, mas faz sentido usar apenas para fins de teste/depuração - certifique-se de nunca habilitar essa opção em produção!```javascript
new LavaDomeJavaScript(root, {
unsafeOpenModeShadow: isThisTestingEnv, // boolean
}).text('123456');
LavaDomeDebug.getTextByRoot(root) === '123456'; // true
stripDistractionFromText()Ao usar web drivers para testes e instruí-los a extrair o texto interno da raiz de uma instância de LavaDome, eles retornarão uma string contendo tanto o segredo quanto o texto de distração do LavaDome.