Esta es una traducción que desde EGA Futura ofrecemos como cortesía a toda la Ohana y comunidad de programadores , consultores , administradores y arquitectos de Salesforce para toda Iberoamérica .
El enlace a la publicación original, lo encontrarás al final de este artículo.
…
El equipo de estándares y plataforma web de Salesforce está defendiendo la creación de nuevas funciones que se ejecutan de forma nativa en los navegadores web. Esta publicación describirá cómo la nueva API ShadowRealm de EcmaScript mejorará los mecanismos de seguridad e integridad de Salesforce, y cómo se puede usar como un componente básico para marcos de virtualización , como Lightning Web Security .
Al igual que con cualquier plataforma, la web espera que sus muchas aplicaciones estén compuestas de muchas maneras diferentes, lo que deja mucho espacio para experiencias creativas de múltiples fuentes. Cuando la Plataforma de Salesforce adopta la web, lleva la idea de composición colectiva a su esencia. Esto sucede cuando nuestros clientes dan forma a la forma en que usan Salesforce con sus personalizaciones más creativas y comparten su experiencia con otros clientes. Esas composiciones terminan en programas con múltiples fuentes, ya sea de diferentes equipos o proveedores, y con una multitud de requisitos ambientales, todos ellos conectados simultáneamente a la plataforma Salesforce.
En las aplicaciones web, todo se comparte dentro de un único entorno global raíz, que está representado por el objeto Ventana principal. Aquí es donde el núcleo de la aplicación de Salesforce se ejecuta en el navegador y se conecta a muchos de sus componentes, incluidos los personalizados por los clientes. Es fundamental preservar la integridad de esta ejecución en su conjunto como lo es mantener la seguridad dentro de cada pieza utilizada para la composición de un cliente.
Las aplicaciones pueden establecer huellas en el ámbito global y en los objetos integrados disponibles. Estas modificaciones pueden variar desde agregar nombres a lo global (p. ej., $
para jQuery) hasta parchear métodos comunes (p. ej., agregar un comportamiento personalizado a Array.prototype.sort
). Estas modificaciones pueden afectar la integridad de una aplicación que está compuesta por muchos componentes y/o bibliotecas.
¿Qué es ShadowRealm?
ShadowRealm está diseñado para permitir la creación de un nuevo contexto de evaluación con su propio objeto global nuevo y su propio conjunto de objetos integrados, proporcionando un mecanismo para ejecutar código JavaScript sin compartir o contaminar los recursos globales con otras partes dentro de esa aplicación.
Este mecanismo ejecuta código JavaScript en el mismo montón que el contexto circundante donde se crea el contexto ShadowRealm. El código se ejecuta de forma síncrona, lo que permite virtualizar las API DOM a las que accede este código que se ejecuta dentro de la instancia de ShadowRealm. Los marcos de virtualización se basan en este mecanismo para la comunicación entre ShadowRealm y los elementos Window.
const sr = new ShadowRealm(); // Establece un nuevo global solo dentro de ShadowRealm sr.evaluate('globalThis.x = "my shadowRealm"'); globalEsto.x = "raíz"; // const srx = sr.evaluate('globalThis.x'); srx; // "mi reino de las sombras" X; // "raíz"
Una instancia de ShadowRealm solo puede transferir valores primitivos de JavaScript (Cadena, Número, BigInt, Símbolo, Booleano, indefinido y nulo) y no permite transferir ningún objeto a través de los límites del reino. Esto es importante porque los objetos llevan referencias de identidad del reino donde se crearon, lo que podría usarse para filtrar información o causar problemas de discontinuidad de identidad. Por ejemplo, un constructor de matriz de la ventana principal es diferente de un constructor de matriz de cualquier otro reino, incluido ShadowRealm. ¡Los objetos de matriz son instancias de su constructor de reino respectivo solamente!
Sin embargo, las instancias de ShadowRealm pueden ajustar y "compartir" valores de función. Esto permite canales de comunicación robustos de ida y vuelta entre los reinos de las sombras.
const sr = new ShadowRealm(); const wrappedFn = sr.evaluate('(x) => globalThis.foo = x'); wrappedFn(42); globalThis.foo; // undefined sr.evaluate('globalThis.foo'); // 42
Las funciones envueltas también pueden enviar otras funciones para que se envuelvan en el ámbito receptor.
const sr = new ShadowRealm(); const wrapFn = sr.evaluate('(x) => globalThis.foo = x'); // La función envuelta recibida por shadowRealm encadenará la llamada // a la función de flecha creada en este dominio raíz wrapFn((y) => globalThis.bar * y); // El reino de las sombras acaba de envolver la función de flecha arriba y // configurarlo como el valor de su respectivo globalThis.foo globalThis.bar = 3; sr.evaluate('globalThis.bar = 0'); // Cuando se llama `foo` del sr, llamará a la función flecha // en este reino y refleja su valor de retorno. sr.evaluar('globalEsto.foo(2)'); // 6
Esta comunicación es síncrona y se puede utilizar para obtener el estado inmediato de los elementos de la página o el estado exacto de una aplicación.
Como el objeto global no se comparte, hay menos problemas de que varios componentes establezcan valores personalizados e inesperados en objetos integrados estándar:
const sr = new ShadowRealm(); // Elimina el constructor Array del objeto global dentro de esta instancia sr.evaluate('eliminar globalThis.Array;'); // verdadero // El constructor de Array actual no se ve afectado tipo de matriz; // "función"
Uso de ShadowRealm sin evaluación de cadenas
ShadowRealm no introduce ningún mecanismo nuevo para evaluar el código JavaScript. ShadowRealm.prototype.evaluate
funciona de manera similar a una eval()
indirecta, con el código ejecutándose en la respectiva instancia de ShadowRealm. Esto significa que la evaluación del código está sujeta a la Política de seguridad de contenido (CSP) existente al igual que la página principal. Por ejemplo, unsafe-eval
impide el uso de ShadowRealm.prototype.evaluate
.
Si la evaluación de la cadena de código no es posible, hay otra forma de inyectar código en una instancia de ShadowRealm. ShadowRealm.prototype.importValue
permite importar un módulo dinámico, como en la expresión import()
, para cargar un módulo y capturar un valor de exportación, incluidas las funciones envueltas.
const sr = new ShadowRealm(); especificador const = './foo.js'; const nombre = 'suma'; // importValue devuelve una promesa que eventualmente se resolverá con // el valor especificado en el nombre del módulo dado. const shadowSum = await sr.importValue(especificador, nombre); sumasombras(1); // ejecuta una operación dentro de shadowRealm y captura el resultado
Los módulos se evalúan por dominio, lo que significa que las modificaciones no compartirán valores ni observarán conjuntos globales de diferentes dominios. Por ejemplo, el módulo de ./foo.js
tiene el siguiente código:
globalEsto.total = 0; función de exportación suma(n) { volver globalEsto.total += n; } función de exportación getTotal() { volver globalEsto.total; }
En este caso, shadowSum
es una función que envuelve sum
cargado dentro del shadow realm y, cuando se llama, solo afecta globalThis.total
desde el shadowRealm respectivo. De la misma manera, si el módulo ./foo.js
se carga en otro dominio, como el dominio de la página, la función de sum
observará el módulo respectivo en el que se cargó.
const sr = new ShadowRealm(); especificador const = './foo.js'; const nombre = 'suma'; const [ shadowSum, shadowGetTotal ] = await Promise.all([ sr.importValue(especificador, nombre), sr.importValue(especificador, 'getTotal') ]); globalEsto.total = 0; sumasombras(10); // 10 sumasombras(20); // 30 sumasombras(30); // 60 globalEsto.total; // 0 sombraObtenerTotal(); // 60 const { sum, getTotal } = esperar importación (especificador); suma(42); // 42 globalEsto.total; // 42 // El valor del reino de las sombras se conserva sombraObtenerTotal(); // 60
El importValue
está diseñado intencionalmente para requerir que se importe un valor del módulo dado como punto de partida para establecer un canal de comunicación con la instancia de ShadowRealm. No devuelve ningún objeto de espacio de nombres de módulo, como la expresión import()
regular, ya que los objetos actualmente no pueden cruzar el límite del reino oculto.
Como el método de evaluate
está sujeto a restricciones de CSP, como unsafe-eval
, el método importValue
está sujeto a restricciones de CSP establecidas en la página, como default-src
. Si esta directiva está presente, la API no podrá cargar el código de esta manera.
Código de bajo nivel y virtualización
La API de ShadowRealm contiene solo dos métodos y está diseñada para usarse en código de bajo nivel. ShadowRealm a menudo se puede utilizar como base para la virtualización o los sistemas de sandboxing de código. La API de ShadowRealm no está diseñada para ser utilizada directamente por un usuario final; requiere una capa de marco en la parte superior, como Lightning Web Security (LWS). LWS utiliza un marco de membranas para comunicar la ejecución de valores y estados a través de ShadowRealms y la ventana principal de la aplicación.
También es probable que la superficie de API incorporada expuesta sea más pequeña en comparación con el objeto de ventana de nivel superior que se ve en la página principal o los de iframes. Es importante destacar que el objeto global en una instancia de ShadowRealm es un objeto ordinario con todas sus propiedades configurables, lo que significa que cualquier propiedad global se puede eliminar y contrasta directamente con las infames propiedades globales infalsificables de iframes, como window.top
y window.location
. . Estas propiedades siempre están presentes en los elementos globales de los iframes y no se pueden eliminar. ShadowRealm evita esto, no solo al no agregar ningún valor infalsificable, sino también al establecer reglas que requieren que cualquiera de los valores proporcionados por el host se pueda eliminar de manera efectiva.
La nueva API establece límites para la ejecución de código que puede aprovechar un lienzo limpio que no solo está listo para los módulos, sino que también se puede usar correctamente en la web para virtualizar la manipulación de DOM que se ejecuta de forma reducida o nula. Eso lo diferencia del código que se ejecutaría sin problemas de integridad en una página limpia. La API de ShadowRealm puede ser una base útil y poderosa para marcos de membrana y otras piezas de encapsulación disponibles en la web.
Hoja de ruta para ShadowRealms
Hay más para mejorar para ShadowRealm, ya que gran parte de esta discusión se inclina hacia bajar la barra para unir un marco de membrana o, tal vez, estandarizar un marco de membrana directamente. Parte de esta discusión sopesa la idea de llevar la serialización a los objetos para ofrecer una solución inteligente que ya está presente en la web hoy, como en los trabajadores web. Otras discusiones incluyen la creación de mecanismos para envolver y desempaquetar promesas, iteradores e iteradores asíncronos a través de los límites del reino de la sombra.
Todas estas ideas son importantes y funcionan como una pieza vital del proceso de estándares para el ecosistema web. El equipo de estándares y plataforma web de Salesforce continúa trabajando en mejoras adicionales para ShadowRealm como una pieza importante del lenguaje JavaScript. TC39 mantiene un repositorio de GitHub con la API de ShadowRealms, el explicador , los hilos de problemas y la versión renderizada actual de su especificación.
Sobre los autores
Leo Balter (él/él) es un gerente de producto sénior que impulsa los estándares y la plataforma web en Salesforce. Como delegado de TC39, Leo actualmente defiende la API de ShadowRealm para asegurarse de que se convierta en parte de ECMAScript. Mientras no trabaja, a Leo le encanta tocar estándares de Jazz en una de sus muchas guitarras.
Rick Waldron (él/él) es un ingeniero de software líder para el marco Lightning Web Security y uno de los campeones de la API de ShadowRealm. Rick se asegura de que todos los estándares de JavaScript estén muy bien probados como responsable de mantenimiento de Test262, el conjunto de pruebas oficial de JavaScript. También toca muchas de sus guitarras en su tiempo libre.
…
Esta es una traducción realizada por EGA Futura, y este es el link a la publicación original: https://developer.salesforce.com/blogs/2022/04/introducing-shadowrealm.html