Vm2: Не застрахован от while (1) {}

Созданный на 2 янв. 2019  ·  19Комментарии  ·  Источник: patriksimek/vm2

Срок действия следующего кода не истечет.

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

Все 19 Комментарий

Скорее всего, для этого нет хорошего решения. NodeJS - это единый процесс. Для защиты while (1) {} требуется несколько процессов, чтобы средство проверки не блокировалось while (1) {}. Может быть, если бы мы смогли возродить проект SpiderNode .......

Это вызвано тестированием Decontextify.value для прототипа гостевого объекта с помощью instanceOf . Модуль Node.js vm конечно, невосприимчив к этому. Патч для бедняков может заключаться в бэкдоре Proxy чтобы мы могли обнаруживать любые прокси-объекты из песочницы, но идеальным подходом было бы просто никогда не доверять никаким объектам и функциям из него и помещать contextxtify.js в песочницу, использование примитивных значений для связи и дескрипторов для ссылок на гостевые объекты.

Просто для людей, без браузера используется дочерний процесс и передача сообщений, чтобы общаться с дочерним процессом, выполняющим ненадежный код. Это немного сложная задача, но после ее выполнения вы будете невосприимчивы к атакам while(1){} . Источник здесь .

Кажется, весь смысл этого проекта в том, чтобы не порождать целую отдельную
Процесс ОС. В противном случае доступно множество решений, которые
более безопасный.

В противном случае доступно множество решений, которые намного безопаснее.

Какие? Я не уверен, что есть лучшая альтернатива VM2 в NodeJS, по крайней мере, я не видел

Сопровождающий этой библиотеки указал на эту альтернативу в выпуске №80:

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

Сам еще не пробовал.

Я запускаю только ненадежный код в дочернем процессе. Не стоит рисковать запускать его в основном экземпляре V8, особенно если вы знаете, что он однопоточный.

Проблема прямого вызова движка V8 заключается в отсутствии модуля импорта. В моем случае мне нужно импортировать модуль запроса, чтобы разрешить операции HTTP. Он также должен быть асинхронным.

Я считаю vm2 + child_process хорошей комбинацией.

Привет,

я и @harelmo создали библиотеку поверх vm2, которая невосприимчива к while(1) {} .

Подобно тому, что упоминал tian-ma, но мы используем рабочие потоки node.js вместо дочерних процессов.

загляните сюда: https://www.npmjs.com/package/isolated-runtime и дайте нам знать, что вы думаете :)

Другой обходной путь - просто отключить Proxy в песочнице, верно?

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

Используя Promise, также можно написать код, который никогда не истекает:

"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);
}

Проблема здесь в том, что .then помещает функцию, которая будет вызвана позже, в очередь микрозадач.
Чтобы исправить это, нам нужно написать наши собственные функции Promise.then и связанные с ними или отключить Promise.

Также это работает:

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

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

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

Так что просто переопределить Promise не получится.
Не знаю, как это исправить.

Пока это остается открытым, мы должны добавить пояснение в README, чтобы предупредить потенциальных пользователей. Эта уязвимость позволяет выйти из песочницы и, таким образом, сводит на нет цель библиотеки.

Файл Readme обновлен https://github.com/patriksimek/vm2/commit/77f5265ab53b87864a312156ee62b1082787e9b0#diff -04c6e90faac2675aa89e2176d2eec7d8. И я не знаю, как это можно использовать для выхода из песочницы, вы можете избежать только тех временных рамок, в которых должен запускаться скрипт.

Возможно, это должна быть отдельная проблема, но почему NodeVM не поддерживает тайм-аут?

@crowder, поскольку в NodeVM существуют setTimeout, setInterval и setImmediate, было бы легко обойти тайм-аут. Может быть, есть и другие причины, но я не работаю с NodeVM, только с ВМ.

@XmiliaH не реализовал бы тайм-аут, чтобы предотвратить, по крайней мере, непреднамеренные бесконечные циклы?
Вредоносная комбинация while (true) + setTimeout по-прежнему будет проблемой, но любой простой непреднамеренный бесконечный цикл, выполненный по ошибке, может быть обработан с помощью поддержки тайм-аута.

Меня беспокоит то, что NodeVM позволяет требовать модули, которые могут быть хост-модулями, и время ожидания при изменении глобального состояния может быть плохим. Кроме того, NodeVM возвращает модуль, и пользователи, скорее всего, будут вызывать функции, предоставляемые модулем, однако тайм-аут будет применяться только к загрузке модуля, а не к вызовам функций.
Если вы хотите вызвать функцию с тайм-аутом, вы можете просто реализовать ее самостоятельно, например

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;
    }
}

Хороший момент @XmiliaH и спасибо за пример
Я вижу, что в вашем примере используется пакет vm, а не vm2
Было бы неплохо иметь возможность использовать vm2 и при этом иметь возможность тайм-аута

@szydan Опубликованный мной код используется VM2 для тайм-аута виртуальной машины. Если бы у NodeVM тоже был тайм-аут, он бы использовал ту же функциональность.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги