• 沙箱:沙箱是一种安全机制,为运行中的程序提供隔离环境,能够安全的执行不受信任的代码,且不影响外部实际代码影响的独立环境。
    • 场景:
      • 低代码平台中,用户提交的各种事件处理逻辑
      • 在线代码编辑器,比如 掘金
      • 插件,比如 figma
      • 开发/生产环境隔离
    • 预防:不在预期内的副作用、全局污染、篡改ui、网络攻击。。。。
    • 问题拆解:
      • 可执行:能够正常执行用户提供的脚本;
        • eval、new function、动态 script 标签、动态import、静态编译、webworker 等等
      • 隔离:沙箱环境内不可访问全局环境,沙箱必须检测并预防哪些不在预期内的代码行为
        • 数据隔离、上下文接口隔离
      • 模拟:提供必要的、严格受控的上下文
    • 实现:

      • with:在当前作用域顶端再加一个作用域(vue 源码中就通过这种方式,在render 函数注入上下文数据),可用于模拟上下文环境
        • 问题:只能保证“能访问啥”,不能有效隔离环境
      • with + proxy:可以实现只允许访问命中上下文及白名单内的数据,不允许访问其它数据;
        • 问题:全局对象,如 document 等,只允许访问其中部分接口,或者接口影响范围需要做限制
      • with + proxy + iframe:iframe 可以创造一个独立浏览器主页面,但完整的执行上下文环境,能完美提供与主页面隔离的 bom、dom 接口
        1. <iframe sandbox="allow-scripts" src="about:blank"></iframe>
    • 为什么 iframe 能确保安全?

      1. h5 新出的 sandbox 可以限制iframe 权限,例如,默认不允许执行脚本等:

    image.png

    • sandbox 基础上,主页面与 iframe 页面之间可以限制为只通过 postMessage 接口通讯,这个接口的好处在于:
      • 只关心明确注册的事件
      • 事件参数会被序列化之后才传输,在对面再反序列化成对象形式,这也就相当于深克隆了,不必担心对象操作的副作用(例如,通过 Object.defineProperty)
      • 例如,可以基于 postMessage + sandbox 属性实现有限度的 fetch 接口,限制动态加载数据的域名白名单,实现既要又要
        • how:看示例代码
    • 用 proxy 等实现一个独立上下文环境,问题:有不少沙箱逃逸方法,例如: ```javascript // 创建一个新的全局函数 (()=>{}).constructor(‘’,’alert(“abc”)’)();

    // 通过原型链 a.b.proto.toString=function (){/ 危险代码 /} a.b.toString()

    1. - 咋办:
    2. - 静态代码分析:基于 js 的动态性,这必然不是一个好方案,但目前社区也没有更好的解决方案了
    3. - iframe 隔离在安全域名,参考 juejin
    4. - 再扩展开来:
    5. - qiankun 也是基于 iframe 实现的沙箱环境,有相关经验的同学可以看看
    6. - 在服务端,用安全环境运行浏览器,参考 [Browserling](https://www.browserling.com/browser-sandbox)
    7. - 自定义浏览器,例如微信公众号浏览器,or 小程序运行时,or 一些 hybrid app
    8. - nodejs 中的沙箱:node 中安全泄露带来的问题更大,环境隔离需求更强
    9. - 应用:云函数、webideLeetCode
    10. - 方案:
    11. - 使用 [VM 模块](https://nodejs.org/api/vm.html),动态编译,沙箱、and 执行代码
    12. ```javascript
    13. const vm = require('vm');
    14. const script = new vm.Script('m + n');
    15. const sandbox = { m: 1, n: 2 };
    16. const context = new vm.createContext(sandbox);
    17. script.runInContext(context);
    1. - `vm` 并不安全,例如:
    1. const vm = require("vm");
    2. const script = new vm.Script(
    3. 'this.constructor.constructor("return process")().stdout.write("fwe") '
    4. );
    5. const sandbox = {};
    6. const context = vm.createContext(sandbox);
    7. script.runInContext(context);
    8. ({}.toString());
    1. - 使用扩展模块 `[vm2](https://github.com/patriksimek/vm2)` —— 支持有限的上下文接口

    sanbox.zip
    资料: