最近手头我的项目利用到了沙箱机制顺便钻研了下 间接上代码~
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
// 不反对多个子利用