简体   繁体   English

在 Node.js 中为动态加载的模块更改全局 Scope

[英]Altering Global Scope for dynamically loaded module in Node.js

Loading a module from a source dynamically:从源动态加载模块:

var src="HERE GOES MY SOURCE"
var Module = module.constructor;
var m = new Module();
m._compile(src, 'a-path-that-does-not-exist');

Need to achieve following:需要达到以下几点:

  1. Pass some variables/functions so that they can be used inside the src script globally.传递一些变量/函数,以便它们可以在src脚本中全局使用。 Can set them in "m.foo", but want the script to use "foo" without using "module.foo".可以在“m.foo”中设置它们,但希望脚本使用“foo”而不使用“module.foo”。 "global.foo" works, but see the point 2. “global.foo”有效,但请参阅第 2 点。
  2. How to restrict the src script from accessing global scope?如何限制src脚本访问全局scope?
  3. How to restrict the src from loading other modules using require or other means.如何限制src使用require或其他方式加载其他模块。
  4. How to restrict the src from running async operations?如何限制src运行异步操作?

All, I can think of is to wrap the script in its own function, kind of like nodejs already does for commonJS modules.所有,我能想到的是将脚本包装在它自己的 function 中,就像 nodejs 已经为 commonJS 模块所做的那样。 This is the regular wrapper.这是常规包装。

(function(exports, require, module, __filename, __dirname) {
// Module code actually lives in here
});

If you wrap that user code with your own wrapper and then when you call it to execute it, you can define your own values for require , module and any other semi-global symbols.如果您使用自己的包装器包装该用户代码,然后当您调用它来执行它时,您可以为requiremodule和任何其他半全局符号定义自己的值。

If you also put 'use strict';如果你也把'use strict'; as the very first line of your wrapper function (before any of the user code), then that will eliminate default assignment to the global object with just something like x = 4 because that will be an error without explicitly defining x first.作为包装器 function 的第一行(在任何用户代码之前),那么这将消除对global object 的默认分配,仅使用x = 4之类的东西,因为如果没有先明确定义x将是一个错误。 If you then also make your own global object and pass it as an argument, that can keep anyone from assigning to the real global object.如果您随后还创建自己的全局 object 并将其作为参数传递,则可以防止任何人分配给真正的全局 object。 I don't think you can prevent implicit read access to pre-existing globals.我认为您不能阻止对预先存在的全局变量的隐式读取访问。

So, your wrapper could look like this:因此,您的包装器可能如下所示:

(function(exports, require, module, __filename, __dirname, global) {
     'use strict';
     // insert user code here before evaluating it with eval()
     // and getting the function which you can then call and pass the desired arguments
});

Then, when you call this function, you pass it the values you want to for all the arguments (something other than the real ones).然后,当您调用此 function 时,您将所有 arguments 的值(不是真实值)传递给它。


Note, it's hard to tell how leak-proof this type of scheme really is.请注意,很难说这种方案的防漏性能到底如何。 Any real security should likely be run in a resource restricted VM.任何真正的安全都应该在资源受限的虚拟机中运行。


Another idea, you could run in a Worker Thread which has it's own virgin set of globals.另一个想法,您可以在具有自己的原始全局变量集的工作线程中运行。 So, you do all of the above and run it in a Worker Thread.因此,您执行上述所有操作并在工作线程中运行它。


Addressing your questions in comments:在评论中解决您的问题:

Does the 'use strict';是否“使用严格”; need to go inside the wrapper function or outside?需要 go 在包装器 function 内部还是外部?

It needs to be the first line of code inside the wrapper function, right before where you insert the user code.它必须是包装器 function 中的第一行代码,就在您插入用户代码的位置之前。 The idea is to force that function scope (where the user code lives) inside that wrapper to be in strict mode to limit some of the things it can do.这个想法是强制 function scope(用户代码所在的位置)在该包装器中处于严格模式,以限制它可以做的一些事情。

Could you explain the "I don't think you can prevent implicit read access to pre-existing globals."?你能解释一下“我认为你不能阻止对预先存在的全局变量的隐式读取访问。”吗? If i provide my own object as global, how can the inner script access preexisting globals?如果我提供自己的 object 作为全局变量,内部脚本如何访问预先存在的全局变量?

Any code, even strict mode code can access pre-existing globals without the global prefix.任何代码,甚至是严格模式代码都可以在没有global前缀的情况下访问预先存在的全局变量。 While you can prevent the code from creating new globals by shadowing it with your own global in the wrapper function arguments and by forcing it into strict mode, you can't prevent strict mode code from reading existing globals because they can do so without the global prefix.虽然您可以通过在包装器 function arguments 并通过强制它进入严格模式来阻止代码创建新的global变量,但您不能阻止严格模式代码读取现有的全局变量,因为它们可以在没有全局变量的情况下这样做字首。 So, if there's a pre-existing global called "foo", then existing code can reference that like:因此,如果有一个预先存在的名为“foo”的全局变量,那么现有代码可以像这样引用它:

 console.log(foo);

or或者

 foo = 12;

If there is no foo in a closer scope, the interpreter will find the foo on the global object and use that.如果在更近的 scope 中没有foo ,解释器将在全局 object 上找到foo并使用它。

Note that strict mode prevents the automatic creation of a new global with something like:请注意,严格模式会阻止自动创建新的全局,例如:

 greeting = "happy birthday"

Could you elaborate more no "resource restricted VM"?您能否详细说明没有“资源受限的虚拟机”?

I was talking about real hardware/OS level VMs that allow you to fully control what resources a process may use (disk access, sockets, memory, hardware, etc...).我说的是真正的硬件/操作系统级别的虚拟机,它们允许您完全控制进程可能使用的资源(磁盘访问、sockets、memory、硬件等)。 It's essentially a virtual computer environment separate from any other VMs on the same system.它本质上是一个与同一系统上的任何其他 VM 分开的虚拟计算机环境。 This is a more rigorous level of control.这是一个更严格的控制水平。

WorkerThread is a very interesting concept. WorkerThread 是一个非常有趣的概念。 will take a look?会看吗? My understanding was that WorkerThreads provide memory isolation and the only way to share data is by sending messages (effectively creating copies)?我的理解是 WorkerThreads 提供 memory 隔离,共享数据的唯一方法是发送消息(有效地创建副本)?

Yes, Worker Threads provide pretty good isolation as they start up a whole new JS engine and have their own globals.是的,工作线程提供了很好的隔离,因为它们启动了一个全新的 JS 引擎并拥有自己的全局变量。 They can shared ArrayBuffers in certain ways (if you choose to do that), but normal JS variables are not accessible across thread boundaries.它们可以以某种方式共享 ArrayBuffers(如果你选择这样做的话),但是普通的 JS 变量不能跨线程边界访问。 They would normally communicate via messaging (which is automatically synchronized through the event queue), but you could also communicate via sockets if you wanted.它们通常会通过消息传递(通过事件队列自动同步)进行通信,但如果需要,您也可以通过 sockets 进行通信。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM