精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

微前端代碼隔離方案,手把手實現一個 JS 沙箱隔離!

開發 前端
js沙箱大量應用在微前端框架執行子應用代碼的場景中。我們這里采用最簡單的方式來模擬一下這個場景。

今天我們一起來探究一下前端 js 沙箱的核心實現邏輯,我們將從以下幾個方面來展開討論:

  1. 準備調試環境,探究沙箱需要解決的問題。
  2. 創建沙箱環境。
  3. 通過 with 語句改變沙箱變量作用域鏈。
  4. 通過 proxy 攔截 with 上下文的get,set操作。

這幾個方面一步一步實現一個簡易的js沙箱。

準備調試環境,探究沙箱需要解決的問題:

js沙箱大量應用在微前端框架執行子應用代碼的場景中。我們這里采用最簡單的方式來模擬一下這個場景。

我們準備一個js文件,這個js文件的內容就模擬微前端應用基座應用的執行環境,在里面通過 var 定義一個全局變量:

圖片圖片

我們準備兩段字符串,字符串的內容就是js代碼,我們假設這兩段代碼就分別代表了兩個子應用的代碼:

圖片圖片

假如現在微前端框架需要執行子應用1的代碼,那么就會 fetch 子應用1的靜態資源服務器,獲取到類似于 subCode1 這樣的一個代碼字符串。執行子應用2也是同理。那么現在第一個問題來了,怎樣自動執行字符串內部的js代碼?在js中有兩種比較常見的方式:

  1. Function:
  2. eval

Function 是js提供的一個內置構造函數,基于它,可以通過字符串,創建出一個js函數,因此我們可以這樣嘗試:

圖片圖片

因為 Function(...)本身就是一個表達式,所以我們可以直接進行調用:

圖片圖片

我們查看一下控制臺:

圖片圖片

可以看到子應用1的代碼就被成功執行了,我們嘗試子應用2的代碼也是同理。

eval是js內置的一個函數,這個函數接收一個字符串,eval函數會將這個字符串作為標準的js代碼進行執行:

圖片圖片

我們查看輸出:

圖片圖片

可以看到子應用代碼同樣被正常執行了。 這樣很方便呀,實際上微前端框架內部也是使用類似的方式來執行子應用的js代碼的,但是這樣會有什么問題呢?

  1. 目前子應用中的變量定義會污染全局環境:

目前我們在子應用中定義的變量在全局環境中可以直接訪問,所以我們需要調整一下 subCode1 以及 subCode2 兩個子應用的測試代碼:

圖片圖片

我們將兩端子應用的測試代碼包裹到了一個立即執行函數中,這樣子應用內部定義的變量就不會污染全局了。大部分構建工具構建的產物也是這種方式。

  1. 在子應用內部可以赤裸裸的訪問 window 對象,并且可以直接對它們進行操作:

圖片圖片

圖片圖片

我們可以直接在子應用2中通過訪問 window 對象來改變 window 對象的內容。如何攔截子應用直接污染瀏覽器宿主環境的 window 對象是實現js沙箱最核心的問題。

創建沙箱環境

我們先編寫一個沙箱構造器函數:

var a = 1

const sandbox = () => {
  return (subCode1) => {
     
  }
}

我們編寫了一個高階函數,這個高階函數返回了一個可以接收并且執行子應用代碼的函數。我們期望如果需要執行子應用的結果代碼,只需要這樣進行調用:

const box = sandbox()

box(子應用1代碼)
box(子應用2代碼)
box(子應用3代碼)

接下來就是要在高階函數中去編寫執行子應用的代碼了,我們沿著沙箱的需求來思考解決方案。 我們的需求就是屏蔽瀏覽器window對象,為了實現這個需求,我們可以在返回的高階函數中編寫如下的邏輯:

const boxCtx = {}

return (subCode1) => {
  const boxFn = `(function (window) {
    ${code}
  })(boxCtx)`
  // 通過eval函數執行子應用代碼
  eval(boxFn)
}

實際上就是我們在父函數中創建了一個沙箱的上下文環境,在高階函數中,將子應用代碼放到一個立即執行函數中去進行執行,立即執行函數的參數就是一個window變量,這樣,當我們在子應用代碼內部訪問 window 的時候,因為作用域鏈的原理,就只會訪問到我們在沙箱環境中設置的 window 參數,而無法訪問到瀏覽器全局的 window 對象了。我們可以測試一下:

sandbox()('(function() { window.testVal1 = "testVal1"; window.a = 2; })()')
console.log(' window.testVal1',  window.testVal1)

圖片圖片

這樣做了之后我們就已經可以攔截子應用中對于 window 對象屬性的 set 操作了。 但是如果我們在子應用中嘗試直接通過變量通過 a 來訪問剛剛設置的值的時候,卻是這樣的結果:

sandbox('(function() { window.a = 2; console.log("ssss", a); })()')

圖片圖片

依然訪問的是全局變量a,原因其實很簡單,因為我們目前構建的沙箱函數內部只有一個 window 變量,并沒有 a 變量。所以js在執行這里的時候只能沿著作用域鏈訪問到全局作用域中的a變量了。要解決這個問題,我們必須確保,我們設置的 window 對象上的所有的屬性全部掛載到沙箱的作用域中。

通過 with語句改變沙箱變量作用域鏈:

with 語句的能力可以這樣理解:在js運行時將指定代碼段的執行上下文設置為指定的對象,從而調整該代碼端的作用域鏈。 使用with,我們可以這樣改動并且測試沙箱代碼:

const boxCtx = { b: "b" }

return (subCode1) => {
  const boxFn = `(function boxFn (window) {
    with(window) { ${code} }
  })(boxCtx)`
  // 通過eval函數執行子應用代碼
  eval(boxFn)
}
sandbox('(function sub1() { window.a = 2; console.log("b", b) })()')

圖片圖片

此時 with 語句使得沙箱部分的作用域鏈變成了類似于這樣的結構:

sub1(子應用函數上下文) ---> window(with語句設置的代碼上下文) ---> boxFn 函數執行上下文 ---> 全局執行上下文

因此當我們直接在子應用內部訪問 a 變量的時候:

圖片圖片

就可以正常訪問子應用內部設置的全局變量了。

但是依然有問題沒有解決,比如我們嘗試執行以下的函數:

sandbox('(function() { window.a = 2; window.console.log("ssss", a); })()')

圖片圖片

原因其實很簡單,因為此時的沙箱的window對象并沒有 console 屬性,要解決這個問題,我們可以嘗試擴展以下沙箱的上下文的內容,一個很暴力的解法就是:

const boxCtx = {
    console
  }

我們可能會想到一個更加簡單的擴展沙箱上下文的方法:

const boxCtx = {
    ...window
  }

這樣做了之后我們再利用 window.console 來輸出 a 的值:

圖片圖片

為什么會是1呢?如果我們此時在控制臺中訪問一下window.a的值會看到一個更加詭異的現象:

圖片圖片

全局的window的a屬性被修改了。

全局window的a屬性被修改的原因其實很簡單,因為瀏覽器宿主的 window 上嵌套了一個 window 屬性,并且這個屬性指向了全局window對象,因此window.window是一個無限嵌套的循環引用:

圖片圖片

正是因為這樣,所以當我們直接使用 ... 淺拷貝一個 window 對象的時候,實際上 嵌套的 window 屬性也就被拷貝過來了,因此此時沙箱上下文是一個類似于這樣的對象:

{
  ...,
  window: {
    ...,
    window
  }
}

因此,當沙箱中查找 window 變量的時候是可以直接在 boxCtx 上查找到,而查找的結果就是全局 window 對象的淺拷貝。因此就導致了我們在沙箱內部對于 window 的所有操作實際上操作在了全局window對象上。因此直接拷貝 window 對象來擴展沙箱上下文的方式是不行的。我們得找其他更加簡單的方案。

通過 proxy 攔截 with 上下文的get,set操作:

我們可以提出這樣的設想,我們在沙箱內部通過 window.xxx 進行 get 的時候,如果 xxx 在沙箱內部的 window 上存在,那么就直接使用該值,如果不存在,就前往 window 對象上去查找 xxx 的值,這樣是不是就可以解決這個問題了呢?而做到這一步的關鍵就是攔截沙箱上下文的 get 操作,因此首先我們將傳遞給 with 語句的上下文對象變成一個 Proxy 代理對象:

const createSandboxCtxProxy = () => {
  return new Proxy({}, {
    get(target, key, receiver) {
      
    },
    set(target, key, value, receiver) {

    }
  })
}

const boxCtx = createSandboxCtxProxy()

緊接著可以這樣去攔截 get 和 set 操作:

get(target, key, receiver) {
      console.log('get', key)
      //優先從代理對象上取值
      if(Reflect.has(target,key)){
         return Reflect.get(target,key);
      }

      //如果找不到,就直接從window對象上取值
      const rawValue = Reflect.get(window,key);
      //其他情況直接返回
      return rawValue
    },
    set(target, key, value, receiver) {
      return Reflect.set(target, key, value)
    },

這樣操作之后我們再次來進行測試:

sandbox('(function() { window.a = 2; window.b = "b"; })()')

圖片圖片

這樣就達到了和改造之前一樣的效果了,緊接著我們這樣測試:

sandbox('(function() { window.a = 2; window.b = "b"; window.console.log("a,b", a, b) })()')

圖片圖片

可以看到 console 對象已經可以正常的訪問到了。那么是不是就大功告成了呢?我們再來試一下 window.alert 這類方法:

sandbox('(function() { window.a = 2; window.b = "b"; window.alert(`a, b: ${a}, ${b}`) })()')

圖片圖片

這個錯誤是因為瀏覽器 window 上的方法在調用的時候函數內部的 this 一定要指向瀏覽器 window 對象。比如我們使用一個更好理解的方式來復原這個錯誤:

圖片圖片

定位到了錯誤的原因,我們就很容易可以解決了,只需要調整 get 方法:

get(target, key, receiver) {
      console.log('get', key)
    //優先從代理對象上取值
    if(Reflect.has(target,key)){
      return Reflect.get(target,key);
    }

    //如果找不到,就直接從window對象上取值
    const rawValue = Reflect.get(window,key);

    //如果兜底的是一個函數,需要綁定window對象,比如window.addEventListener
    if(typeof rawValue === 'function'){
      const valueStr = rawValue.toString();
      if(!/^function\s+[A-Z]/.test(valueStr) && !/^class\s+/.test(valueStr)){
        return rawValue.bind(window); // 所有 window 上非構造函數調用時候的 this 綁定window對象
      }
    }

    //其他情況直接返回
    return rawValue
    },

再次測試:

圖片圖片

問題已經解決了。至此我們就一步步最簡化的實現了一個js沙箱。

責任編輯:武曉燕 來源: 程序員Sunday
相關推薦

2020-05-19 10:45:31

沙箱前端原生對象

2022-06-28 15:29:56

Python編程語言計時器

2022-09-22 12:38:46

antd form組件代碼

2021-12-29 11:38:59

JS前端沙箱

2021-06-22 10:43:03

Webpack loader plugin

2022-11-07 18:36:03

組件RPC框架

2020-08-12 09:07:53

Python開發爬蟲

2024-02-06 10:04:49

Express框架repo

2019-08-26 09:25:23

RedisJavaLinux

2021-11-10 11:40:42

數據加解密算法

2020-12-02 12:29:24

Vue無限級聯樹形

2023-11-24 16:57:53

2023-04-26 12:46:43

DockerSpringKubernetes

2017-07-19 13:27:44

前端Javascript模板引擎

2022-10-19 14:16:18

樣式隔離前綴css

2014-01-22 09:19:57

JavaScript引擎

2022-08-26 08:01:38

DashWebJavaScrip

2016-11-01 09:46:04

2020-12-15 08:58:07

Vue編輯器vue-cli

2021-09-26 16:08:23

CC++clang_forma
點贊
收藏

51CTO技術棧公眾號

亚洲精品视频自拍| 久久亚洲图片| 亚洲国产成人一区| 成人免费观看在线| 五月婷婷深深爱| 日韩精品一二三| 美女视频久久黄| 亚洲精品国产成人av在线| 久久毛片亚洲| 18欧美乱大交hd1984| 国产精品一区免费观看| 涩涩视频在线观看| 精品99视频| 正在播放亚洲1区| 成人欧美精品一区二区| av免费在线一区| 亚洲自拍偷拍av| 日韩av不卡播放| 亚洲经典一区二区三区| 免播放器亚洲一区| 98精品国产高清在线xxxx天堂| 永久免费观看片现看| 狼人精品一区二区三区在线| 51精品国自产在线| 久久国产乱子伦免费精品| 综合图区亚洲| 久久久久久久国产精品影院| 51国偷自产一区二区三区的来源| 樱花视频在线免费观看| 在线成人欧美| 久久成人一区二区| 激情五月深爱五月| 蜜臀久久99精品久久一区二区| 日韩欧美亚洲另类制服综合在线| 在线免费观看视频黄| a级片免费在线观看| 亚洲人亚洲人成电影网站色| 蜜桃精品久久久久久久免费影院 | 欧美三级网色| 天堂中文资源在线观看| 国产sm精品调教视频网站| 国产精品视频一区二区三区四| 麻豆久久久久久久久久| 亚洲精品极品| 久久久免费av| 国产性生活网站| 欧美在线亚洲综合一区| 久热在线中文字幕色999舞| a资源在线观看| 精品免费在线| 国产亚洲精品成人av久久ww| 丰腴饱满的极品熟妇| 亚洲精品国产动漫| 亚洲九九九在线观看| 男生裸体视频网站| 亚州国产精品| 亚洲欧美日韩久久久久久| 无码人妻精品一区二区三区温州| 麻豆一区一区三区四区| 亚洲国产精久久久久久久| 尤物网站在线观看| 美国十次av导航亚洲入口| 亚洲国产福利在线| 亚洲第一香蕉网| 秋霞影视一区二区三区| 日韩精品欧美激情| 国产精成人品免费观看| 成人影院天天5g天天爽无毒影院| 在线成人一区二区| 黄色香蕉视频在线观看| 午夜国产欧美理论在线播放| 欧美精品久久久久久久| 成人精品免费在线观看| 日韩综合一区二区| 成人国产精品一区二区| www黄色网址| 99精品久久免费看蜜臀剧情介绍| 久久涩涩网站| 日本在线看片免费人成视1000| 亚洲色图第一区| 国产片侵犯亲女视频播放| 国产美女高潮在线| 欧亚洲嫩模精品一区三区| 久久人人爽av| 果冻天美麻豆一区二区国产| 亚洲精品在线91| 99re6热在线精品视频| 综合一区av| …久久精品99久久香蕉国产| 天堂免费在线视频| 国产精品一区在线观看乱码| 好吊色欧美一区二区三区四区| 国产大学生校花援交在线播放 | 亚洲国产精品www| 在线中文字幕电影| 色综合天天综合网天天看片| 思思久久精品视频| 精品欧美午夜寂寞影院| 日韩在线观看免费网站| 四虎永久在线精品| 久久机这里只有精品| 国产精品免费一区二区| 99re在线视频| 午夜精品久久一牛影视| 亚洲免费黄色网| 人妖一区二区三区| 久久久99久久精品女同性| 草久久免费视频| 国产美女精品在线| 日韩欧美一区二区三区久久婷婷| 永久免费网站在线| 欧美主播一区二区三区美女| 伊人久久一区二区三区| 外国成人免费视频| 国产成人精品电影久久久| 精品美女www爽爽爽视频| 久久精品视频一区二区| 亚洲 欧美 综合 另类 中字| 日韩在线电影| 亚洲人成电影网| 日本最新中文字幕| 国产美女久久久久| 亚洲一区二区三区免费观看| 成人性生活av| 日韩av在线最新| 久草视频手机在线观看| 精品在线你懂的| 日韩aⅴ视频一区二区三区| 成人免费观看在线观看| 日韩一区二区视频| 美国一级片在线观看| 日韩高清在线电影| 久久超碰亚洲| a毛片不卡免费看片| 欧美videofree性高清杂交| 亚洲AV成人无码精电影在线| 蜜芽一区二区三区| 亚洲精品二区| 国产在视频一区二区三区吞精| 亚洲色图综合久久| 国产精品免费精品一区| 99re热这里只有精品免费视频| 男人添女荫道口女人有什么感觉| 国产日韩一区二区三免费高清| 色噜噜久久综合伊人一本| 又污又黄的网站| 欧美激情中文不卡| 亚洲激情在线观看视频| 精品一区不卡| 国产精品久久久久高潮| 高清毛片在线看| 欧美日韩美少妇| 永久免费看片视频教学| 久久99久国产精品黄毛片色诱| 亚洲日本japanese丝袜| 欧美黑粗硬大| 久久激情五月丁香伊人| 国产精品-色哟哟| 亚洲色欲色欲www| 久久久久无码精品| 亚洲高清毛片| 久久久久久久有限公司| 暖暖成人免费视频| 在线色欧美三级视频| 中文字幕人妻一区二区在线视频| 国产精品―色哟哟| 国产精品igao网网址不卡| 国产精品草草| 久久精品美女| 丁香婷婷久久| 欧美高清性猛交| 神马午夜电影一区二区三区在线观看 | 欧美亚洲天堂| 日韩成人中文字幕在线观看| 五月天婷婷导航| 国产精品视频第一区| 亚洲高清视频免费| 日韩一级在线| 天天综合狠狠精品| 欧美日本三级| 91精品国产自产91精品| 成人18在线| 欧美一区二区黄色| 少妇一级淫片免费放中国 | 亚洲国产第一页| 一级黄色在线观看| 亚洲人成网站精品片在线观看| 无码人妻精品一区二区三区99不卡| 羞羞视频在线观看欧美| 一区二区三区免费看| 好吊妞视频这里有精品 | 91香蕉视频污| 天天爽人人爽夜夜爽| 午夜精品久久久久99热蜜桃导演| 精品国产二区在线| 亚洲精品第一| 97国产一区二区精品久久呦| 日韩毛片久久久| 日韩精品免费综合视频在线播放 | 亚洲国产日韩综合一区| 一区二区亚洲视频| 国产精品jizz在线观看麻豆| 美女精品视频| 日韩在线观看免费网站| 日韩国产福利| 日韩精品中午字幕| 在线观看国产黄| 日韩欧美国产黄色| 免费在线观看亚洲| 国产精品国产自产拍高清av| 国产成人无码一区二区在线观看 | 一区二区三区少妇| 国产在线一区二区综合免费视频| www.亚洲天堂网| 狠狠噜噜久久| 91香蕉视频网址| 国产亚洲一卡2卡3卡4卡新区 | 亚洲最快最全在线视频| 亚洲av熟女国产一区二区性色 | 黄色三级生活片| 99精品欧美一区二区三区小说| aaaaa黄色片| 国产一区二区在线看| 15—17女人毛片| 久久综合图片| 日本一区二区黄色| 激情综合在线| 欧洲精品在线播放| 欧美freesex交免费视频| 四虎永久在线精品免费一区二区| 中国av一区| 久久亚洲一区二区| 激情小说亚洲色图| 国产综合 伊人色| www.豆豆成人网.com| 91九色露脸| 日韩黄色av| 91黄色国产视频| 日韩成人久久| 97超碰最新| 视频二区欧美| 超碰97在线资源| 亚洲一级大片| 97久久人人超碰caoprom欧美 | 欧美日韩一区二区三| 首页亚洲中字| 欧美日韩国产三区| 精品久久中文| 一区二区在线不卡| 99久久亚洲精品| 超碰免费在线公开| 亚洲国产一区二区在线观看| 97超碰免费观看| 欧美成人一品| 六月婷婷在线视频| 中文久久精品| 国产视频一区二区视频| 秋霞午夜av一区二区三区| wwwwww.色| 久久99精品久久久| 欧美色图校园春色| 成人精品视频一区二区三区尤物| 手机在线成人av| 久久久www免费人成精品| 成人免费无遮挡无码黄漫视频| 国产日韩v精品一区二区| 亚洲一级理论片| 亚洲理论在线观看| 日韩av黄色片| 色综合天天综合狠狠| 中文字幕一区二区在线视频| 91精品黄色片免费大全| 空姐吹箫视频大全| 亚洲美女在线看| 日本在线看片免费人成视1000| 欧美激情一二区| 成人性生活视频| 成人有码视频在线播放| 国内精品偷拍| 亚洲欧洲一区二区在线观看| 欧美成人首页| 男女视频一区二区三区| 国产美女精品人人做人人爽| 国产伦精品一区二区免费| 中文字幕免费不卡| 国产亚洲欧美精品久久久久久| 色香蕉成人二区免费| 国产精品久久久久久久久久久久久久久久久久 | 国产aⅴ一区二区三区| 亚洲精品videossex少妇| 国产小视频福利在线| 欧美成人免费在线视频| 性感女国产在线| 亚洲mm色国产网站| 亚洲影院天堂中文av色| 自拍偷拍视频在线| 国产日产高清欧美一区二区三区| gogogo高清免费观看在线视频| 成人激情文学综合网| 四虎影视一区二区| 亚洲成人免费影院| 亚洲一级黄色大片| 亚洲精品理论电影| 国产网站在线免费观看| 欧美一区二区三区四区在线| 精品国产18久久久久久二百| 免费在线成人av| 欧美精品99| 亚洲欧美国产中文| 91免费小视频| 久久久久久免费观看| 欧美日韩三级一区| 丝袜+亚洲+另类+欧美+变态| 美女av一区二区| 日韩在线电影| 五月天久久综合网| 亚洲欧美日韩国产一区二区| 无码人妻丰满熟妇区毛片蜜桃精品 | 在线不卡日本v二区707| 国产精品观看在线亚洲人成网| 久久人人爽人人爽人人片av不| 异国色恋浪漫潭| 捆绑变态av一区二区三区| 小早川怜子久久精品中文字幕| 天天综合网天天综合色| www.综合色| 欧美人与物videos| 国产一区二区三区国产精品| 亚洲精品成人久久久998| 老司机精品福利视频| 熟妇人妻久久中文字幕| 亚洲一区二区在线免费看| 国产女人18毛片水18精| 日韩视频在线免费观看| 秋霞国产精品| 日韩欧美视频第二区| 久久久久.com| 久久亚洲AV无码专区成人国产| 欧美日韩免费网站| 偷拍自拍在线| 欧美亚洲国产视频小说| 欧美福利在线播放网址导航| 日本xxxxxxxxxx75| 成人av手机在线观看| 国产亚洲精品久久久久久打不开 | 欧美激情综合| 超级砰砰砰97免费观看最新一期 | 中文字幕亚洲欧美在线| 日韩三区免费| 天天综合色天天综合色hd| 美国一区二区三区在线播放| аⅴ天堂中文在线网| 精品视频1区2区3区| 日本在线免费| 成人av免费在线看| 亚洲青涩在线| 人妻丰满熟妇aⅴ无码| 91高清在线观看| 伊人免费在线| 91亚洲国产成人精品性色| 欧美精品大片| 国产真实乱人偷精品| 色又黄又爽网站www久久| 成人全视频高清免费观看| 国产精品亚洲综合天堂夜夜| 91精品综合| 亚洲精品激情视频| 日韩欧美中文字幕在线观看 | 国产亚洲欧美一区在线观看| 波多野结衣电车| 久久久国产在线视频| 91成人入口| 国产裸体舞一区二区三区| 国产精品私房写真福利视频| 国产视频在线观看视频| 性欧美亚洲xxxx乳在线观看| 国内精品视频在线观看| 日韩av一卡二卡三卡| 婷婷一区二区三区| 懂色av中文在线| 91中文字精品一区二区| 羞羞答答国产精品www一本| 成人无码精品1区2区3区免费看 | 欧美日韩国产综合新一区 | 韩国三级电影久久久久久| 久久不见久久见国语| 国产女同无遮挡互慰高潮91| 亚洲国产精品久久人人爱蜜臀| 九色在线视频| www.成人av.com| 视频一区二区欧美| 九九热精品免费视频| 亚洲色图国产精品| 精品国产一区二区三区性色av| 91精品91久久久中77777老牛| 中文字幕一区av| 手机亚洲第一页| 91久久伊人青青碰碰婷婷| 久久亚洲国产精品一区二区| 久久久久成人网站|