前端沙箱简介
沙箱,即sandbox,顾名思义,就是让你的程序跑在一个隔离的环境下,不对外界的其他程序造成影响
Nodejs Sandbox
在nodejs中主要是依赖于vm模块
const vm = require('vm');
const x = 1;
const sandbox = { x: 1 };
vm.createContext(sandbox); // 创建沙箱
const code = 'x += 40; var y = 1;';
vm.runInContext(code, sandbox);
console.log(sandbox.x); // 41
console.log(sandbox.y); // 1
console.log(x); // 1;
可以通过传入Object.create(null)防止通过原型链逃逸
const vm = require('vm');
const x = 1;
const sandbox = Object.create(null);
sandbox.x=1
vm.createContext(sandbox); // Contextify the sandbox.
const code = 'x += 40; var y = 1;';
vm.runInContext(code, sandbox);
console.log(sandbox.x); // 41
console.log(sandbox.y); // 1
console.log(x); // 1;
借助iframe实现沙箱
<iframe sandbox src="..."></iframe>
遇到的限制
- script脚本不能执行
- 不能发送ajax请求
- 不能使用本地存储,即localStorage,cookie等
- 不能创建新的弹窗和window
- 不能发送表单
- 不能加载额外插件比如flash等
但可以对这个iframe标签进行一些配置
然后就可以通过postMessage进行通信,但需要注意不要让执行代码访问到contentWindow对象
with + new Function
with的块级作用域下,变量访问会优先查找你传入的参数对象,之后再往上找,所以相当于你变相监控到了代码中的“变量访问”
function compileCode(src) {
src = 'with (exposeObj) {' + src + '}'
return new Function('exposeObj', src)
}
function compileCode(src) {
src = `with (exposeObj) { ${src} }`
return new Function('exposeObj', src)
}
function proxyObj(originObj) {
let exposeObj = new Proxy(originObj, {
has: (target, key) => {
if (["console", "Math", "Date"].indexOf(key) >= 0) {
return target[key]
}
if (!target.hasOwnProperty(key)) {
throw new Error(`Illegal operation for key ${key}`)
}
return target[key]
},
})
return exposeObj
}
function createSandbox(src, obj) {
let proxy = proxyObj(obj)
compileCode(src).call(proxy, proxy) //绑定this 防止this访问window
}
const testObj = {
value: 1,
a: {
b: { c: 1 }
}
}
// 访问原型链实现了沙箱逃逸
createSandbox(`a.b.__proto__.toString = ()=>{
console.log(a)
};a.b.__proto__.toString()`, testObj)
with + new Function 还是有很多潜在问题的,没有完全的隔离上下文,没有完全独立的执行进程,所以会导致很多潜在问题
参考:说说JS中的沙箱