Incluir a la barrera: Fortalecer las aplicaciones con SandBox
Ha pasado más de una semana desde CVE-2023-4863: Se ha hecho público el desbordamiento del búfer Heap en WebP, lo que ha causado una avalancha de nuevos lanzamientos en programas para el renderizado de imágenes webp
: macOS, iOS, Chrome, Firefox y varias distribuciones Linux han recibido actualizaciones. Tras las investigaciones realizadas por Citizen Lab, se ha descubierto que un iPhone utilizado por una "organización de la sociedad civil unicada en Washington DC" estuvo bajo ataque por medio de una vulnerabilidad de cero-clicks en iMessage.
Electron, también, entró en acción y publicó nuevas versiones el mismo día: Si tu aplicación renderiza cualquier contenido proporcionado por el usuario, debes actualizar tu versión de Electron - v27.0.0-beta.2, v26.2.1, v25.8.1, v24.8.3 y v22.3.23, todas contienen una versión corregida de libwebp
, la librería responsable de renderizar imágenes webp
.
Ahora que estamos enterados de que una interacción tan inocente como "renderizar una imagen" es una actividad potencialmente peligrosa, aprovechamos esta oportunidad para recordar a todos que Electron incluye un sandbox de procesos que limita el radio de explosión del siguiente gran ataque — sin importar lo que sea.
El sandbox ha estado disponible desde Electron v1 y está activado por defecto en v20, pero sabemos que varias aplicaciones (especialmente aquellas que están disponibles desde hace tiempo) podrían tener un sandbox: false
en cualquier parte del código – o un nodeIntegration: true
que, igualmente, desactiva el sandbox cuando no hay un ajuste de sandbox
explícito. Eso es comprensible: si has estado con nosotros durante un largo tiempo, probablemente has disfrutado el poder de lanzar un require("child_process")
o require("fs")
en el mismo código que ejecuta tu HTML/CSS.
Antes de hablar sobre cómo migrar al sandbox, primero discutamos por qué lo quieres.
El sandbox pone una jaula dura alrededor de todos los procesos de renderizado, garantizando que sin importar lo que suceda dentro, el código es ejecutado en un entorno restringido. Como concepto, es mucho más viejo que Chromium y es proporcionado como una característica en todos los sistemas operativos. El sandbox de Electron y Chromium es construido en base a estas características del sistema. Incluso si nunca has mostrado contenido generado por el usuario, deberías considerar la posibilidad de que tu renderizado puede verse comprometido: Escenarios tan complejos como los ataques a la cadena de suministros y tan sencillos como pequeños errores, pueden causar que tu renderizado realice acciones que no planeabas.
El entorno de pruebas hace que ese escenario sea mucho menos aterrador: un proceso dentro consigue usar libremente ciclos de CPU y memoria — eso es todo. Los procesos no pueden escribir en el disco o mostrar sus propias ventanas. En el caso de nuestro libwep
error, el sandbox se asegura de que un atacante no pueda instalar o ejecutar malware. De hecho, en el caso del ataque Pegasus original contra el iPhone, de los empleados. el ataque se dirigió específicamente a un proceso de imagen que no es de arena para obtener acceso al teléfono, rompiendo primero los límites del iMessage normalmente encendido. Cuando un CVE como el de este ejemplo es anunciado, todavía tienes que actualizar tus aplicaciones Electron a una versión segura, pero mientras tanto, la cantidad de daño que un atacante puede causar es muy limitada.
Migrar una aplicación de vainilla Electron de sandbox: false
a sandbox: true
es una empresa. Lo sé, porque a pesar de haber escrito personalmente el primer borrador de las Directrices de Seguridad Electron, No he conseguido migrar una de mis propias aplicaciones para usarla. Esto ha cambiado este fin de semana y les recomiendo que lo cambien también.
Hay dos cosas que tienes que tomar en cuenta:
-
Si estás usando código de Node.js en scripts de
preload
o enWebContents
, necesitas mover toda esa interacción de Node.js al proceso principal (o, si te sientes elegante, a un utility process). Dado lo poderosos que se han vuelto los renderizadores, es muy probable que la gran mayoría de tu código no necesite refactorización.Consulta nuestra documentación sobre Comunicación entre procesos (IPC). En mi caso, moví mucho código y lo envolví en
ipcRenderer.invoke()
yipcMain.handle()
, pero el proceso fue sencillo y rápido. Ten un poco de cuidado con tus APIs aquí: si construyes una API llamadaexecuteCodeAsRoot(code)
, el sandbox no protegerá mucho a tus usuarios. -
Dado que habilitar el sandbox desactiva la integración de Node.js en tus scripts de preload, ya no puedes usar
require("../my-script")
. En otras palabras, tu script de preload necesita ser un solo archivo.Hay múltiples formas de hacer eso: Webpack, esbuild, parcel y rollup harán el trabajo. Yo utilicé el excelente plugin Webpack para Electron Forge, los usuarios del también popular
electron-builder
pueden usarelectron-webpack
.
En resumen, todo el proceso me tomó alrededor de cuatro días (y eso incluye mucho tiempo pensando cómo manejar el enorme poder de Webpack, ya que decidí aprovechar la oportunidad para refactorizar mi código de muchas otras maneras también).