Срок действия следующего кода не истечет.
const {VM} = require('vm2');
new VM({timeout:1}).run(`
function main(){
while(1){}
}
new Proxy({}, {
getPrototypeOf(t){
global.main();
}
})`);
Скорее всего, для этого нет хорошего решения. 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 тоже был тайм-аут, он бы использовал ту же функциональность.