Vm2: No es inmune a while (1) {}

Creado en 2 ene. 2019  ·  19Comentarios  ·  Fuente: patriksimek/vm2

El siguiente código no expirará.

const {VM} = require('vm2');
new VM({timeout:1}).run(`
        function main(){
        while(1){}
    }
    new Proxy({}, {
        getPrototypeOf(t){
            global.main();
        }
    })`);
bug confirmed help wanted

Todos 19 comentarios

Probablemente no haya una buena solución para esto. NodeJS es un solo proceso. while (1) {} la protección requiere multiproceso para que el verificador no sea bloqueado por while (1) {}. Tal vez si pudiéramos reavivar el proyecto SpiderNode .......

Esto se debe a la prueba Decontextify.value para el prototipo del objeto invitado con instanceOf . El módulo Node.js vm es, por supuesto, inmune a esto. El parche de un pobre podría ser la puerta trasera Proxy para que podamos detectar cualquier objeto Proxy del sandbox, pero un enfoque ideal sería simplemente nunca confiar en ningún objeto y función de él y poner contextify.js en sandbox, utilizando valores primitivos para comunicarse y manejadores para hacer referencia a objetos invitados.

Solo para que la gente lo vea, sin navegador utiliza un proceso secundario y el paso de mensajes para hablar con el niño que ejecuta el código que no es de confianza. Es un poco una tarea de configuración, pero una vez hecho esto, serás inmune a los ataques while(1){} . La fuente está aquí .

El objetivo de este proyecto parece ser no generar un
Proceso del sistema operativo. De lo contrario, hay muchas soluciones disponibles que son mucho
más seguro.

De lo contrario, hay muchas soluciones disponibles que son mucho más seguras.

¿Cuáles? No estoy seguro de que haya una alternativa mejor a VM2 en NodeJS, al menos no que yo haya visto

El mantenedor de esta biblioteca señaló esta alternativa en el número 80:

https://github.com/laverdet/isolated-vm

Yo no lo he probado todavía.

Solo ejecuto código que no es de confianza en el proceso secundario. No puede arriesgarse a ejecutarlo en la instancia principal de V8, especialmente cuando sabe que es de un solo hilo.

El problema de llamar directamente al motor V8 es la falta de módulo de importación. En mi caso, necesito importar el módulo de solicitud para permitir operaciones HTTP. También tiene que ser asincrónico.

Encuentro vm2 + child_process una buena combinación.

Oye,

@harelmo y while(1) {} .

Similar a lo que tian-ma mencionó, pero usamos subprocesos de trabajo de node.js en lugar de procesos secundarios.

Eche un vistazo aquí: https://www.npmjs.com/package/isolated-runtime y háganos saber lo que piensa :)

Otra solución alternativa sería simplemente deshabilitar Proxy dentro de la caja de arena, ¿verdad?

const vm = new VM({
    sandbox: {
        Proxy: undefined
    },
    timeout: 100
});

Usando Promise también es posible escribir código que nunca se agota:

"use strict";
const {VM} = require('vm2');
const untrusted = '(' + function(){
    Promise.resolve().then(a=>{
        while(1){}
    });
}+')()';
try{
    console.log(new VM({timeout:10}).run(untrusted));
}catch(x){
    console.log(x);
}

El problema aquí es que .then pondrá en cola la función que se llamará más tarde en la cola de microtask.
Para solucionar este problema, necesitamos escribir nuestra propia Promesa, luego y funciones relacionadas o deshabilitar Promesa.

También esto funciona:

const {VM} = require('vm2');

const script = '(' + function() {
    (async function x(){
        await {then: y=>y()};
        while(1){}
    })();
}+')()';

new VM({timeout:10}).run(script);

Así que simplemente anular Promise no funcionará.
No tengo idea de cómo solucionar este problema.

Si bien esto permanece abierto, debemos agregar una aclaración al README para advertir a los usuarios potenciales. Esta vulnerabilidad le permite a uno escapar de la caja de arena y, por lo tanto, frustra el propósito de la biblioteca.

El archivo Léame se actualizó https://github.com/patriksimek/vm2/commit/77f5265ab53b87864a312156ee62b1082787e9b0#diff -04c6e90faac2675aa89e2176d2eec7d8. Y no sé cómo se podría usar esto para escapar de la caja de arena, solo puede escapar del período de tiempo previsto en el que debe ejecutarse el script.

Quizás este debería ser su propio problema, pero ¿por qué NodeVM no admite el "tiempo de espera"?

@crowder dado que en NodeVM existe setTimeout, setInterval y setImmediate, sería fácil eludir el tiempo de espera. Quizás también haya otras razones, pero no trabajo con NodeVM, solo VM.

@XmiliaH, ¿la implementación de un tiempo de espera no evitaría al menos bucles infinitos no deseados?
La combinación maliciosa while (true) + setTimeout seguiría siendo un problema, pero cualquier bucle infinito no intencionado realizado por error podría manejarse mediante el tiempo de espera

Mi preocupación es que NodeVM permite requerir módulos que pueden ser módulos de host y el tiempo de espera mientras cambian el estado global puede ser malo. Además, NodeVM devuelve un módulo y es muy probable que los usuarios llamen a las funciones expuestas por el módulo, sin embargo, el tiempo de espera solo se aplicaría a la carga del módulo y no a las llamadas a funciones.
Si desea llamar a una función con un tiempo de espera, puede implementarla usted mismo como

function doWithTimeout(fn, timeout) {
    let ctx = CACHE.timeoutContext;
    let script = CACHE.timeoutScript;
    if (!ctx) {
        CACHE.timeoutContext = ctx = vm.createContext();
        CACHE.timeoutScript = script = new vm.Script('fn()', {
            filename: 'timeout_bridge.js',
            displayErrors: false
        });
    }
    ctx.fn = fn;
    try {
        return script.runInContext(ctx, {
            displayErrors: false,
            timeout
        });
    } finally {
        ctx.fn = null;
    }
}

Buen punto @XmiliaH y gracias por el ejemplo.
Veo que su ejemplo está usando el paquete vm y no vm2
Sería bueno poder usar vm2 y aún poder agotarlo

@szydan VM2 usa el código que publiqué para agotar el tiempo de espera de la VM. Si el NodeVM también tuviera un tiempo de espera, usaría la misma funcionalidad.

¿Fue útil esta página
0 / 5 - 0 calificaciones