Javascript创建沙箱

用途

在隔离环境中,用以测试不受信任的文件或运行用户输入等行为的工具

实现原理

构建with块级作用域限制局部变量

with语句 能改变变量的作用域链,使得程序在查找变量值时,都是先在with指定的对象中查找,然后再往上查找

使用ES6的Proxy限制变量向上查找

Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。

当with块级作用域内的调用某一变量时,若此变量在sanbox中有定义,返回sandbox中的定义,否则直接返回undefined。这样起到了隔离代码执行环境的作用

结果返回

在sandbox中预设某个变量用于接收执行代码的返回值。这里是我的实现,不太优雅,酌情使用。

实现代码

// 给多个sanbox做一个缓存
sandboxProxies = new WeakMap()

runInSandBox (src : string) {
  src = 'with (sandbox) { ' + src + '}'
  const code = new Function('sandbox', src)
  
  function has (target, key) {  
    return true
  }
  
  function get (target, key) {  
    if (key === Symbol.unscopables) return undefined
    return target[key]
  }

  return (sandbox) => {
    if (!sandboxProxies.has(sandbox)) {
      const sandboxProxy = new Proxy(sandbox, { has, get })
      sandboxProxies.set(sandbox, sandboxProxy)
    }
    let sbp : any = sandboxProxies.get(sandbox)
    code(sbp)
    return sbp
  }
}

调用方法

let sandbox = {
  window: {},
  Object,
  JSON,
  Math,
  console,
  document,
  returnData: {}
}
let code = "returnData = { 'a': 'hello world' }"
let d = runInSandBox(code)(sandbox)
console.log(d.returnData)

你可能感兴趣的:(前端)