7

berial 久违更新:沙箱逃逸

 3 years ago
source link: https://zhuanlan.zhihu.com/p/284428468
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

berial 久违更新:沙箱逃逸

前端玩票,高产玩具,fre,fard,berial,ep……

halo 大家好,俺是 132,今天啥也没干,纠结了一天去哪家公司的问题……

晚上来自未来公司的小哥哥给 berial 提了一个问题:webpack代码切割生成的js/css能够做到沙箱隔离吗? · Issue #62 · berialjs/berial

经典的沙箱逃逸问题……

沙箱逃逸

简单说就是你在沙箱里跑 js,但是这段 js 往沙箱外面插了一个 js,这个 js 就逃逸到外面了

哎呀我好困,大家自行体会伐

解决思路

解决逃逸问题主要有两种方式

  1. Proxy 劫持 dom 操作

这个思路是 qiankun 正在使用的方式,主要是劫持 createElement 等方法,然后让 script 不要插到外面

话说我在 fard 中也是用 Proxy 劫持 dom 操作,然后传送到主线程

这个思路要想搞得好,必须有一个苛刻的封装才行,否则就很容易变成一种 case by case 的 hack 行为

2. MutationObserver

使用 MutationObserver 检测 document 对象,对当前的 shadow dom 之外的操作进行劫持,然后在下一个 tick 的时候塞到沙箱里跑

  new MutationObserver((mutations) => {
    mutations.forEach(async (m: any) => {
      switch (m.type) {
        case 'childList':
          if (m.target !== host) {
            for (let i = 0; i < m.addedNodes.length; i++) {
              const node = m.addedNodes[i]
              if (node instanceof HTMLScriptElement) {
                const src = node.getAttribute('src') || ''
                const script = await request(src)
                scriptsNextTick.push(script)
              }
            }
          }
          break
        default:
      }
    })
  }).observe(document, { childList: true, subtree: true })

这个思路的实现不难,但整个过程不需要和 qiankun 那样憋屈

总结

以上,berial 的沙箱从理论上可以说近乎完美了……

使用 Proxy 劫持 window,使用 MutationObserver 侦测 document

前阵子我写了一个一个回答:当前市面上的微前端是否有真正解决方案?

我说 berial,qiankun 这个思路的微前端,最后被一些新的提案所替代,但是我也不后悔写了 berial ……

因为,作为一个前端,还能在 runtime 做什么呢?没那么多东西可以做的……

纵使未来微前端被内置,berial 这套代码也仍旧有意义

最后放一下 berial 的 github:berialjs/berial

对微前端感兴趣的可以随便玩~


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK