SeguridadNode.jsCapabilitiesConfinamientoArquitectura

No afirmes que una frontera de seguridad aguanta: demuéstrala

Publicado el 2026-08-26 · Xiliux

Un sistema tiene que ejecutar un trozo de código que no controlas —un plugin, una dependencia, algo generado— y quieres garantizar que ese código no pueda tocar el sistema de archivos ni lanzar procesos. No que "no deba": que no pueda, mecánicamente. Eso es confinamiento por capabilities, y es uno de los problemas centrales de la seguridad de un runtime.

Diseñarlo y demostrarlo son dos cosas distintas, y confundirlas es caro.

Un diseño es una afirmación

Puedes escribir un documento impecable: "el acceso a fs y a lanzar procesos se controla así, con estos mecanismos, bajo este modelo de amenaza". Es trabajo real y necesario. Pero es una afirmación. Y el modo de fallo de una frontera de seguridad es que parece que aguanta hasta que no aguanta —silencioso, invisible en las pruebas, visible solo cuando alguien la cruza—.

En seguridad, una afirmación no verificada tiene exactamente la forma de una arquitectura preciosa y equivocada. El diseño puede asumir que un gancho del cargador de módulos dispara en un punto donde en realidad no dispara, y todo el razonamiento que cuelga de ahí es correcto y no sirve de nada.

Los mecanismos existen, y son varios

En Node, por nombrar un runtime concreto, hay al menos tres capas, y no son intercambiables:

Elegir bien entre ellas es el diseño. Pero elegir bien no prueba que la elección aguante contra el árbol de dependencias real que vas a correr.

Demostrar en vez de afirmar

La alternativa a firmar un diseño es entregar un arnés de confinamiento: código no confiable que intenta alcanzar la capability peligrosa —abrir un archivo, lanzar un proceso— contra el runtime real y su árbol de dependencias real, y un registro que muestra que cada intento quedó bloqueado. O, si algo se escapa, exactamente dónde.

La diferencia no es cosmética. "Creo que está confinado" y "aquí está la evidencia de que un intento de leer un archivo del sistema desde el plugin devolvió permiso denegado" son afirmaciones de peso muy distinto. La segunda es la disciplina que uso para todo lo demás aplicada a la seguridad: cruzar la frontera del programa y medir lo que sale, no lo que crees que sale.

La parte honesta

Hay una tentación de firmar la frontera desde una autoridad que no has ganado —porque el diseño se ve bien, porque los mecanismos existen—. La disciplina honesta es la contraria: lo que puedes respaldar hoy, lo respaldas; lo que depende de un detalle del runtime que no dominas, no lo afirmas de memoria: lo validas empíricamente, y lo que no se puede demostrar todavía se marca como la costura a co-revisar, no se esconde.

Una frontera demostrada tapa exactamente el hueco que una afirmada deja abierto. Y para quien tiene que confiar en el confinamiento, un arnés que ataca su propia frontera y guarda la evidencia vale más que la palabra del que la diseñó.

Preguntas frecuentes

¿Qué es el confinamiento por capabilities?

Controlar qué puede alcanzar un fragmento de código: leer o escribir archivos, lanzar procesos, abrir red. En vez de confiar en que el código se porte bien, se le niega mecánicamente el acceso a lo peligroso, de modo que no pueda tocarlo aunque quiera.

¿Qué mecanismos hay, por ejemplo en Node?

El modelo de permisos nativo (--permission, --allow-fs-*) a nivel de proceso; SES / Hardened JavaScript (Compartments, lockdown()) para confinar qué importa cada módulo; y la interceptación del cargador de módulos. Cada uno cubre una capa distinta y no son intercambiables.

¿Por qué demostrar y no afirmar?

Porque el modo de fallo de una frontera es silencioso: parece que aguanta hasta que no aguanta, y no se nota en las pruebas. Un arnés que lanza el ataque contra la propia frontera y guarda el resultado convierte 'creo que está' en 'aquí está la evidencia de que está'.

¿Y si no dominas los internals del runtime?

Es la parte honesta: no se afirma desde una autoridad que no se ha ganado. Lo que se puede respaldar hoy se respalda; lo que depende de un detalle del runtime que no dominas se valida empíricamente contra el runtime real, y lo que no se puede demostrar todavía se marca como costura a co-revisar, no se esconde.

← Ver más artículosCotizar un proyecto