最近手头项目应用到了沙箱机制顺便研究了下 直接上代码~
function sandbox(code) {
code= 'with (sandbox) {' + code + '}'
return new Function('sandbox', code)
}
let str = 'let a = 10;console.log(a)'
sandbox(str)({})
//而es6的proxy则可以解决这个问题,proxy可以设置访问拦截器,于是with再加上proxy几乎完美解决js沙箱机制。当然,还是有机制可以绕过,有大神发现Symbol.unScopables可以不受with的影响,所以要另外处理Symbol.unScopables:
class ProxySandbox{
constructor(){
const rawWindow = window
const fakeWindow = {}
const proxy = new Proxy(fakeWindow, {
set(target,prop,value){
target[prop] = value
return true
},
get(target,prop){
return target[prop] || fakeWindow[prop]
}
})
this.proxy = proxy
}
}
const sandbox1 = new ProxySandbox()
const sandbox2 = new ProxySandbox()
window.a = 1
((window) => {
window.a = 'hello'
console.log(window.a)
})(sandbox1.proxy)
((window) => {
window.a = 'world'
console.log(window.a)
})(sandbox1.proxy)
上面的例子应用到es6的proxy,目前js沙箱能做到的最好的沙箱机制,适用于多个应用,但是也有兼容性的限制
快照沙箱
class snapShotSandbox{
proxy = window // window 属性
modifyPropsMap = {} // 记录在window上的修改
active()
active(){ // 激活沙箱
this.windowSnapshot = {} // 拍照
for(const prop in window){
if(window.hasOwnProperty(prop)){
this.windowSnapshot[prop] = window[prop]
}
}
Object.keys(this.modifyPropsMap).forEach(prop => {
window[prop] = this.modifyPropsMap[prop]
})
}
inactive(){ // 失活沙箱
for(const prop in window){
if(window.hasOwnProperty(prop)){
if(window[prop] !== this.windowSnapshot[prop]){
this.modifyPropsMap[prop] = window[prop]
window[prop] = this.windowSnapshot[prop]
}
}
}
}
}
const sandbox = new snapShotSandbox()
((window) => {
window.a = 1
window.b = 2
console.log(window.a, window.b)
sandbox.inactive()
console.log(window.a, window.b)
sandbox.active()
console.log(window.a, window.b)
})(sandbox.proxy) // sandbox.proxy 就是 window
// 不支持多个子应用
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。