
Aislamiento y encapsulación seguros de árboles DOM aprovechando ShadowDOM
⚠️ EXPERIMENTAL [WIP] - ÚSALO BAJO TU PROPIO RIESGO (más información)
Prueba LavaDome: visita la aplicación demo, abre la consola y haz todo lo que esté en tu poder para robar el secreto dentro de la instancia de LavaDome (reporta tu éxito)
Bajo los estándares web actuales, no existe una forma establecida de aislar selectivamente subárboles del DOM de manera segura. En otras palabras, no podemos controlar el acceso a secciones del DOM otorgando acceso a algunas partes mientras se lo bloqueamos a otras, si comparten el mismo entorno de ejecución de JavaScript.
Vivimos en un mundo donde ya no podemos confiar en el código de nuestras propias aplicaciones, y la ejecución del mismo origen no garantiza seguridad. Para proteger secretos en el frontend, debemos poder mostrar contenido al usuario y, al mismo tiempo, garantizar que no pueda ser comprometido por código JavaScript que se ejecute bajo el mismo origen.

Actualmente, este contenido sensible simplemente se adjunta al DOM una vez exportado, lo que lo hace totalmente accesible para todas las entidades que se ejecutan en la misma aplicación. Es decir, secciones del código que no deberían tener acceso a la clave privada podrían extraerla fácilmente en texto plano, siempre que el código malicioso tenga acceso al DOM.
Pero no te preocupes. Creemos que este es un problema solucionable 👇
LavaDome actualmente es compatible con JavaScript Vanilla y React (con más en camino)
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} />
</>;
}
Además del nodo raíz, todos los constructores aceptan un segundo argumento opcional de opciones:```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
Debido a las limitaciones del núcleo web, para integrar LavaDome de forma segura, hay algunas cosas a tener en cuenta que requieren un esfuerzo activo por parte del desarrollador que lo integra:
#### Orden de ejecución
LavaDome, como cualquier otro software de seguridad de JavaScript, siempre es vulnerable al código que se ejecuta antes que él.
Esto significa que, excepto por el código en el que confiamos absolutamente, LavaDome debe ser la primera pieza de código en cargarse en el programa de la aplicación web.
Aunque esto no significa que el desarrollador deba usarlo de inmediato (sino solo cuando lo necesite), sí debe incluir el programa lo antes posible.
Para hacerlo correctamente (de forma segura), debe ser la primera declaración import/require en todo el programa:```javascript
import '@lavamoat/lavadome-react';
import 'other-stuff';
console.log('Program starts here');
De esa manera garantizamos que LavaDome tenga tiempo de prepararse para su uso seguro.
Ten en cuenta que esto aplica de igual forma al resto de los paquetes de LavaDome y no solo a @lavamoat/lavadome-react (por lo que importar más de uno de ellos es innecesario).
Salta a Seguridad (codificación defensiva) para aprender más.
Debido a los ataques de canal lateral y las limitaciones web, importar fuentes remotas puede ser una técnica exitosa contra LavaDome. Dado que está incrustado en los reinos de CSS, abordar este problema a través de LavaDome no es posible actualmente.
Afortunadamente, esto se puede abordar de manera efectiva usando la directiva font-src de CSP.
Para mitigar esta forma de ataque, asegúrate de que tu aplicación web no permita la carga de fuentes desde servidores desconocidos.
Salta a Seguridad (canal lateral) para aprender más.
El texto proporcionado a LavaDome por el desarrollador debe ser 100% impredecible, de lo contrario puede ser atacado y filtrado.
Entonces, si tu aplicación debe presentar "your key is 234789", esto significa que tu estructura DOM debería ser:```html
your key is 234789
y no debe ser:```html
<span> <lavadome>your key is 234789</lavadome> </span>
Salta a Security(findability) para aprender más.
Integrar LavaDome podría ser complicado en el contexto de las pruebas, porque dado que LavaDome hace un buen trabajo ocultando el secreto, ¡también lo oculta bastante bien de tus pruebas!
Para integrar LavaDome con éxito en tu entorno de pruebas, puede que necesites ayuda de LavaDomeDebug, que es exportado por @lavamoat/lavadome-core:```javascript
// IMPORT/USE FOR TESTING/DEBUGGING PURPOSES ONLY - NEVER IN PRODUCTION!
import { LavaDomeDebug } from '@lavamoat/lavadome-core';
A continuación se muestran algunos de los métodos de utilidad de depuración que exporta `LavaDomeDebug` y que pueden ayudarte a probar componentes basados en `LavaDome`:
#### `getTextByRoot()`
Dado un root adjunto de `LavaDome`, `getTextByRoot()` extraerá y reconstruirá recursivamente el secreto interno. Para permitir eso, la instancia de `LavaDome` debe inicializarse originalmente con la opción UNSAFE `@unsafeOpenModeShadow`, que hace que las sombras internas de `LavaDome` sean accesibles desde el exterior.
Naturalmente, esto es UNSAFE y deja `LavaDome` totalmente vulnerable, pero tiene sentido usarlo solo con fines de prueba/depuración - asegúrate de nunca habilitar esta opción en producción.```javascript
new LavaDomeJavaScript(root, {
unsafeOpenModeShadow: isThisTestingEnv, // boolean
}).text('123456');
LavaDomeDebug.getTextByRoot(root) === '123456'; // true
stripDistractionFromText()