Vm2: ليس محصنًا من حين (1) {}

تم إنشاؤها على ٢ يناير ٢٠١٩  ·  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 هي عملية مفردة. بينما (1) {} تتطلب الحماية عمليات متعددة حتى لا يتم حظر المدقق من حين لآخر (1) {}. ربما إذا تمكنا من إحياء مشروع SpiderNode .......

هذا ناتج عن اختبار Decontextify.value للنموذج الأولي لكائن الضيف باستخدام instanceOf . وحدة Node.js vm محصنة ضد هذا بالطبع. قد يكون تصحيح الرجل الفقير هو الباب الخلفي Proxy حتى نتمكن من اكتشاف أي كائنات Proxy من sandbox ، ولكن الأسلوب المثالي هو عدم الوثوق مطلقًا بأي كائنات ووظائف منه ووضع Contextify.js في وضع الحماية ، استخدام القيم الأولية للتواصل والمقابض للإشارة إلى كائنات الضيف.

فقط لكي يراها الناس ، يستخدم المستعرض عملية الأطفال وتمرير الرسائل للتحدث مع الطفل الذي يقوم بتشغيل الكود غير الموثوق به. إنها مهمة إعداد قليلاً ، ولكن بمجرد الانتهاء من ذلك ، ستكون محصنًا ضد هجمات while(1){} . المصدر هنا .

يبدو أن بيت القصيد من هذا المشروع هو عدم إنتاج منفصلة كاملة
عملية نظام التشغيل. خلاف ذلك ، هناك العديد من الحلول المتاحة والتي تكون كثيرة
أكثر أمنا.

بخلاف ذلك ، هناك العديد من الحلول المتاحة والتي تكون أكثر أمانًا.

اي واحدة؟ لست متأكدًا من وجود بديل أفضل لـ VM2 في NodeJS ، على الأقل ليس كما رأيته

أشار مشرف هذه المكتبة إلى هذا البديل في العدد رقم 80:

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

لم أجربها بنفسي بعد.

أنا فقط أقوم بتشغيل رمز غير موثوق به في العملية التابعة. لا يمكن المخاطرة بتشغيله في مثيل V8 الرئيسي خاصة عندما تعلم أنه مترابط واحد.

مشكلة استدعاء محرك V8 مباشرة هي عدم وجود وحدة استيراد. في حالتي ، أحتاج إلى استيراد وحدة الطلب للسماح بعمليات HTTP. كما يجب أن تكون غير متزامنة.

أجد أن vm2 + child_process مزيج جيد.

مهلا،

لقد قمت أنا و while(1) {} .

على غرار ما ذكره tian-ma ، لكننا نستخدم سلاسل العامل node.js بدلاً من العمليات الفرعية.

ألق نظرة هنا: https://www.npmjs.com/package/isolated-runtime وأخبرنا برأيك :)

سيكون الحل الآخر هو تعطيل Proxy داخل sandbox ، أليس كذلك؟

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

المشكلة هنا هي أن. ثم سينتظر الوظيفة ليتم استدعاؤها لاحقًا في قائمة انتظار المهام الدقيقة.
لإصلاح هذا ، نحتاج إلى كتابة 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);

لذا فإن مجرد تجاوز الوعد لن ينجح.
لا توجد فكرة عن كيفية إصلاح هذا.

بينما يظل هذا مفتوحًا ، يجب أن نضيف توضيحًا إلى README لتحذير المستخدمين المحتملين. تسمح هذه الثغرة الأمنية للهروب من الصندوق الرمل وبالتالي فهي تتعارض مع الغرض من المكتبة.

تم تحديث الملف التمهيدي https://github.com/patriksimek/vm2/commit/77f5265ab53b87864a312156ee62b1082787e9b0#diff -04c6e90faac2675aa89e2176d2eec7d8. ولا أعرف كيف يمكن استخدام هذا للهروب من وضع الحماية ، يمكنك فقط الهروب من الإطار الزمني المقصود الذي يجب تشغيل النص فيه.

ربما يجب أن تكون هذه مشكلتها الخاصة ، ولكن لماذا لا تدعم NodeVM "timeout"؟

crowder نظرًا لأن setTimeout و setInterval & setImmediate موجودة في NodeVM ، فسيكون من السهل التحايل على المهلة. ربما هناك أسباب أخرى أيضًا ، لكنني لا أعمل مع NodeVM ، فقط VM.

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 يستخدم

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات