这次给大家带来Node.js 沙箱环境使用步骤详解,Node.js 沙箱环境使用的注意事项有哪些,下面就是实战案例,一起来看一下。
node官方文档里提到node的vm模块可以用来做沙箱环境执行代码,对代码的上下文环境做隔离。
A common use case is to run the code in a sandboxed environment. The sandboxed code uses a different V8 Context, meaning that it has a different global object than the rest of the code.
先看一个例子
const vm = require('vm'); let a = 1; var result = vm.runInNewContext('var b = 2; a = 3; a + b;', {a}); console.log(result); // 5 console.log(a); // 1 console.log(typeof b); // undefined
沙箱环境中执行的代码对于外部代码没有产生任何影响,无论是新声明的变量b,还是重新赋值的变量a。 注意最后一行的代码默认会被加上return关键字,因此无需手动添加,一旦添加的话不会静默忽略,而是执行报错。
const vm = require('vm'); let a = 1; var result = vm.runInNewContext('var b = 2; a = 3; return a + b;', {a}); console.log(result); console.log(a); console.log(typeof b);
如下所示
evalmachine.<anonymous>:1 var b = 2; a = 3; return a + b; ^^^^^^ SyntaxError: Illegal return statement at new Script (vm.js:74:7) at createScript (vm.js:246:10) at Object.runInNewContext (vm.js:291:10) at Object.<anonymous> (/Users/xiji/workspace/learn/script.js:3:17) at Module._compile (internal/modules/cjs/loader.js:678:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10) at Module.load (internal/modules/cjs/loader.js:589:32) at tryModuleLoad (internal/modules/cjs/loader.js:528:12) at Function.Module._load (internal/modules/cjs/loader.js:520:3) at Function.Module.runMain (internal/modules/cjs/loader.js:719:10)</anonymous></anonymous>
除了runInNewContext外,vm还提供了runInThisContext和runInContext两个方法都可以用来执行代码 runInThisContext无法指定context
const vm = require('vm'); let localVar = 'initial value'; const vmResult = vm.runInThisContext('localVar += "vm";'); console.log('vmResult:', vmResult); console.log('localVar:', localVar); console.log(global.localVar);
由于无法访问本地的作用域,只能访问到当前的global对象,因此上面的代码会因为找不到localVal而报错
evalmachine.<anonymous>:1 localVar += "vm"; ^ ReferenceError: localVar is not defined at evalmachine.<anonymous>:1:1 at Script.runInThisContext (vm.js:91:20) at Object.runInThisContext (vm.js:298:38) at Object.<anonymous> (/Users/xiji/workspace/learn/script.js:3:21) at Module._compile (internal/modules/cjs/loader.js:678:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10) at Module.load (internal/modules/cjs/loader.js:589:32) at tryModuleLoad (internal/modules/cjs/loader.js:528:12) at Function.Module._load (internal/modules/cjs/loader.js:520:3) at Function.Module.runMain (internal/modules/cjs/loader.js:719:10)</anonymous></anonymous></anonymous>
如果我们把要执行的代码改成直接赋值的话就可以正常运行了,但是也产生了全局污染(全局的localVar变量)
const vm = require('vm'); let localVar = 'initial value'; const vmResult = vm.runInThisContext('localVar = "vm";'); console.log('vmResult:', vmResult); // vm console.log('localVar:', localVar); // initial value console.log(global.localVar); // vm
runInContext在传入context参数上与runInNewContext有所区别 runInContext传入的context对象不为空而且必须是经vm.createContext()处理过的,否则会报错。 runInNewContext的context参数是非必须的,而且无需经过vm.createContext处理。 runInNewContext和runInContext因为有指定context,所以不会向runInThisContext那样产生全局污染(不会产生全局的localVar变量)
const vm = require('vm'); let localVar = 'initial value'; const vmResult = vm.runInNewContext('localVar = "vm";'); console.log('vmResult:', vmResult); // vm console.log('localVar:', localVar); // initial value console.log(global.localVar); // undefined
当需要一个沙箱环境执行多个脚本片段的时候,可以通过多次调用runInContext方法但是传入同一个vm.createContext()返回值实现。
超时控制及错误捕获
vm针对要执行的代码提供了超时机制,通过指定timeout参数即可以runInThisContext为例
const vm = require('vm'); let localVar = 'initial value'; const vmResult = vm.runInThisContext('while(true) { 1 }; localVar = "vm";', { timeout: 1000});
vm.js:91 return super.runInThisContext(...args); ^ Error: Script execution timed out. at Script.runInThisContext (vm.js:91:20) at Object.runInThisContext (vm.js:298:38) at Object.<anonymous> (/Users/xiji/workspace/learn/script.js:3:21) at Module._compile (internal/modules/cjs/loader.js:678:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10) at Module.load (internal/modules/cjs/loader.js:589:32) at tryModuleLoad (internal/modules/cjs/loader.js:528:12) at Function.Module._load (internal/modules/cjs/loader.js:520:3) at Function.Module.runMain (internal/modules/cjs/loader.js:719:10) at startup (internal/bootstrap/node.js:228:19)</anonymous>
可以通过try catch来捕获代码错误
const vm = require('vm'); let localVar = 'initial value'; try { const vmResult = vm.runInThisContext('while(true) { 1 }; localVar = "vm";', { timeout: 1000 }); } catch(e) { console.error('executed code timeout'); }
延迟执行
vm除了即时执行代码之外,也可以先编译然后过一段时间再执行,这就需要提到vm.Script了。其实无论是runInNewContext、runInThisContext还是runInThisContext,背后其实都创建了Script,从之前的报错信息就可以看出来 接下来我们就用vm.Script来重写本文开头的例子
const vm = require('vm'); let a = 1; var script = new vm.Script('var b = 2; a = 3; a + b;'); setTimeout(() => { let result = script.runInNewContext({a}); console.log(result); // 5 console.log(a); // 1 console.log(typeof b); // undefined }, 300);
除了vm.Script,node在9.6版本中新增了vm.Module也可以做到延迟执行,vm.Module主要用来支持ES6 module,而且它的context在创建的时候就已经绑定好了,关于vm.Module目前还需要在命令行使用flag来启用支持
node --experimental-vm-module index.js
vm作为沙箱环境安全吗?
vm相对于eval来说更安全一些,因为它隔离了当前的上下文环境了,但是尽管如此依然可以访问标准的JS API和全局的NodeJS环境,因此vm并不安全,这个在官方文档里就提到了
The vm module is not a security mechanism. Do not use it to run untrusted code
请看下面的例子
const vm = require('vm'); vm.runInNewContext("this.constructor.constructor('return process')().exit()") console.log("The app goes on...") // 永远不会输出
为了避免上面这种情况,可以将上下文简化成只包含基本类型,如下所示
let ctx = Object.create(null); ctx.a = 1; // ctx上不能包含引用类型的属性 vm.runInNewContext("this.constructor.constructor('return process')().exit()", ctx);
针对原生vm存在的这个问题,有人开发了vm2包,可以避免上述问题,但是也不能说vm2就一定是安全的
const {VM} = require('vm2'); new VM().run('this.constructor.constructor("return process")().exit()');
虽然执行上述代码没有问题,但是由于vm2的timeout对于异步代码不起作用,所以下面的代码永远不会执行结束。
const { VM } = require('vm2'); const vm = new VM({ timeout: 1000, sandbox: {}}); vm.run('new Promise(()=>{})');
即使希望通过重新定义Promise的方式来禁用Promise的话,还是一个可以绕过的
const { VM } = require('vm2'); const vm = new VM({ timeout: 1000, sandbox: { Promise: function(){}} }); vm.run('Promise = (async function(){})().constructor;new Promise(()=>{});');
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
Vue项目webpack打包部署时Tomcat刷新报404错误问题如何处理
以上是Node.js 沙箱环境使用步骤详解的详细内容。更多信息请关注PHP中文网其他相关文章!

C 和JavaScript通过WebAssembly实现互操作性。1)C 代码编译成WebAssembly模块,引入到JavaScript环境中,增强计算能力。2)在游戏开发中,C 处理物理引擎和图形渲染,JavaScript负责游戏逻辑和用户界面。

JavaScript在网站、移动应用、桌面应用和服务器端编程中均有广泛应用。1)在网站开发中,JavaScript与HTML、CSS一起操作DOM,实现动态效果,并支持如jQuery、React等框架。2)通过ReactNative和Ionic,JavaScript用于开发跨平台移动应用。3)Electron框架使JavaScript能构建桌面应用。4)Node.js让JavaScript在服务器端运行,支持高并发请求。

Python更适合数据科学和自动化,JavaScript更适合前端和全栈开发。1.Python在数据科学和机器学习中表现出色,使用NumPy、Pandas等库进行数据处理和建模。2.Python在自动化和脚本编写方面简洁高效。3.JavaScript在前端开发中不可或缺,用于构建动态网页和单页面应用。4.JavaScript通过Node.js在后端开发中发挥作用,支持全栈开发。

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。 1)C 用于解析JavaScript源码并生成抽象语法树。 2)C 负责生成和执行字节码。 3)C 实现JIT编译器,在运行时优化和编译热点代码,显着提高JavaScript的执行效率。

JavaScript在现实世界中的应用包括前端和后端开发。1)通过构建TODO列表应用展示前端应用,涉及DOM操作和事件处理。2)通过Node.js和Express构建RESTfulAPI展示后端应用。

JavaScript在Web开发中的主要用途包括客户端交互、表单验证和异步通信。1)通过DOM操作实现动态内容更新和用户交互;2)在用户提交数据前进行客户端验证,提高用户体验;3)通过AJAX技术实现与服务器的无刷新通信。

理解JavaScript引擎内部工作原理对开发者重要,因为它能帮助编写更高效的代码并理解性能瓶颈和优化策略。1)引擎的工作流程包括解析、编译和执行三个阶段;2)执行过程中,引擎会进行动态优化,如内联缓存和隐藏类;3)最佳实践包括避免全局变量、优化循环、使用const和let,以及避免过度使用闭包。

Python更适合初学者,学习曲线平缓,语法简洁;JavaScript适合前端开发,学习曲线较陡,语法灵活。1.Python语法直观,适用于数据科学和后端开发。2.JavaScript灵活,广泛用于前端和服务器端编程。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

SublimeText3 英文版
推荐:为Win版本,支持代码提示!

WebStorm Mac版
好用的JavaScript开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

SublimeText3 Linux新版
SublimeText3 Linux最新版