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

基于 WebWorker 封裝 JavaScript 沙箱

開發 前端
如果你不知道 web worker 是什么或者從未了解過,可以查看 Web Workers API 。簡而言之,它是一個瀏覽器實現的多線程,可以運行一段代碼在另一個線程,并且提供與之通信的功能。

  [[430837]]

在前文 基于quickjs 封裝 JavaScript 沙箱 已經基于 quickjs 實現了一個沙箱,這里再基于 web worker 實現備用方案。如果你不知道 web worker 是什么或者從未了解過,可以查看 Web Workers API 。簡而言之,它是一個瀏覽器實現的多線程,可以運行一段代碼在另一個線程,并且提供與之通信的功能。

實現 IJavaScriptShadowbox

事實上,web worker 提供了 event emitter 的 api,即 postMessage/onmessage ,所以實現非常簡單。

實現分為兩部分,一部分是在主線程實現 IJavaScriptShadowbox ,另一部分則是需要在 web worker 線程實現 IEventEmitter

主線程的實現

  1. import { IJavaScriptShadowbox } from "./IJavaScriptShadowbox"
  2.  
  3. export class WebWorkerShadowbox implements IJavaScriptShadowbox { 
  4.   destroy(): void { 
  5.     this.worker.terminate(); 
  6.   } 
  7.  
  8.   private worker!: Worker; 
  9.   eval(code: string): void { 
  10.     const blob = new Blob([code], { type: "application/javascript" }); 
  11.     this.worker = new Worker(URL.createObjectURL(blob), { 
  12.       credentials: "include"
  13.     }); 
  14.     this.worker.addEventListener("message", (ev) => { 
  15.       const msg = ev.data as { channel: string; data: any }; 
  16.       // console.log('msg.data: ', msg) 
  17.       if (!this.listenerMap.has(msg.channel)) { 
  18.         return
  19.       } 
  20.       this.listenerMap.get(msg.channel)!.forEach((handle) => { 
  21.         handle(msg.data); 
  22.       }); 
  23.     }); 
  24.   } 
  25.  
  26.   private readonly listenerMap = new Map<string, ((data: any) => void)[]>(); 
  27.   emit(channel: string, data: any): void { 
  28.     this.worker.postMessage({ 
  29.       channel: channel, 
  30.       data, 
  31.     }); 
  32.   } 
  33.   on(channel: string, handle: (data: any) => void): void { 
  34.     if (!this.listenerMap.has(channel)) { 
  35.       this.listenerMap.set(channel, []); 
  36.     } 
  37.     this.listenerMap.get(channel)!.push(handle); 
  38.   } 
  39.   offByChannel(channel: string): void { 
  40.     this.listenerMap.delete(channel); 
  41.   } 

web worker 線程的實現

  1. import { IEventEmitter } from "./IEventEmitter"
  2.  
  3. export class WebWorkerEventEmitter implements IEventEmitter { 
  4.   private readonly listenerMap = new Map<string, ((data: any) => void)[]>(); 
  5.  
  6.   emit(channel: string, data: any): void { 
  7.     postMessage({ 
  8.       channel: channel, 
  9.       data, 
  10.     }); 
  11.   } 
  12.  
  13.   on(channel: string, handle: (data: any) => void): void { 
  14.     if (!this.listenerMap.has(channel)) { 
  15.       this.listenerMap.set(channel, []); 
  16.     } 
  17.     this.listenerMap.get(channel)!.push(handle); 
  18.   } 
  19.  
  20.   offByChannel(channel: string): void { 
  21.     this.listenerMap.delete(channel); 
  22.   } 
  23.  
  24.   init() { 
  25.     onmessage = (ev) => { 
  26.       const msg = ev.data as { channel: string; data: any }; 
  27.       if (!this.listenerMap.has(msg.channel)) { 
  28.         return
  29.       } 
  30.       this.listenerMap.get(msg.channel)!.forEach((handle) => { 
  31.         handle(msg.data); 
  32.       }); 
  33.     }; 
  34.   } 
  35.  
  36.   destroy() { 
  37.     this.listenerMap.clear(); 
  38.     onmessage = null
  39.   } 

使用

主線程代碼

  1. const shadowbox: IJavaScriptShadowbox = new WebWorkerShadowbox(); 
  2. shadowbox.on("hello", (name: string) => { 
  3.   console.log(`hello ${name}`); 
  4. }); 
  5. // 這里的 code 指的是下面 web worker 線程的代碼 
  6. shadowbox.eval(code); 
  7. shadowbox.emit("open"); 

web worker 線程代碼

  1. const em = new WebWorkerEventEmitter(); 
  2. em.on("open", () => em.emit("hello""liuli")); 

下面是代碼的執行流程示意圖

限制 web worker 全局 api

經大佬 JackWoeker 提醒,web worker 有許多不安全的 api,所以必須限制,包含但不限于以下 api

  • fetch
  • indexedDB
  • performance

事實上,web worker 默認自帶了 276 個全局 api,可能比我們想象中多很多。

Snipaste_2021-10-24_23-05-18

有篇 文章 闡述了如何在 web 上通過 performance/SharedArrayBuffer api 做側信道攻擊,即便現在 SharedArrayBuffer api 現在瀏覽器默認已經禁用了,但天知道還有沒有其他方法。所以最安全的方法是設置一個 api 白名單,然后刪除掉非白名單的 api。

  1. // whitelistWorkerGlobalScope.ts 
  2.  
  3. /** 
  4.  
  5. * 設定 web worker 運行時白名單,ban 掉所有不安全的 api 
  6.  
  7. */ 
  8.  
  9. export function whitelistWorkerGlobalScope(list: PropertyKey[]) { 
  10.  
  11. const whitelist = new Set(list); 
  12.  
  13. const all = Reflect.ownKeys(globalThis); 
  14.  
  15. all.forEach((k) => { 
  16.  
  17. if (whitelist.has(k)) { 
  18.  
  19. return
  20.  
  21.  
  22. if (k === "window") { 
  23.  
  24. console.log("window: ", k); 
  25.  
  26.  
  27. Reflect.deleteProperty(globalThis, k); 
  28.  
  29. }); 
  30.  
  31.  
  32. /** 
  33.  
  34. * 全局值的白名單 
  35.  
  36. */ 
  37.  
  38. const whitelist: ( 
  39.  
  40. | keyof typeof global 
  41.  
  42. | keyof WindowOrWorkerGlobalScope 
  43.  
  44. "console" 
  45.  
  46. )[] = [ 
  47.  
  48. "globalThis"
  49.  
  50. "console"
  51.  
  52. "setTimeout"
  53.  
  54. "clearTimeout"
  55.  
  56. "setInterval"
  57.  
  58. "clearInterval"
  59.  
  60. "postMessage"
  61.  
  62. "onmessage"
  63.  
  64. "Reflect"
  65.  
  66. "Array"
  67.  
  68. "Map"
  69.  
  70. "Set"
  71.  
  72. "Function"
  73.  
  74. "Object"
  75.  
  76. "Boolean"
  77.  
  78. "String"
  79.  
  80. "Number"
  81.  
  82. "Math"
  83.  
  84. "Date"
  85.  
  86. "JSON"
  87.  
  88. ]; 
  89.  
  90. whitelistWorkerGlobalScope(whitelist); 

然后在執行第三方代碼前先執行上面的代碼

  1. import beforeCode from "./whitelistWorkerGlobalScope.js?raw"
  2.  
  3. export class WebWorkerShadowbox implements IJavaScriptShadowbox { 
  4.  
  5. destroy(): void { 
  6.  
  7. this.worker.terminate(); 
  8.  
  9.  
  10. private worker!: Worker; 
  11.  
  12. eval(code: string): void { 
  13.  
  14. // 這行是關鍵 
  15.  
  16. const blob = new Blob([beforeCode + "\n" + code], { 
  17.  
  18. type: "application/javascript"
  19.  
  20. }); 
  21.  
  22. // 其他代碼。。。 
  23.  
  24.  

由于我們使用 ts 編寫源碼,所以還必須將 ts 打包為 js bundle,然后通過 vite 的 ?raw 作為字符串引入,下面吾輩寫了一個簡單的插件來完成這件事。

  1. import { defineConfig, Plugin } from "vite"
  2.  
  3. import reactRefresh from "@vitejs/plugin-react-refresh"
  4.  
  5. import checker from "vite-plugin-checker"
  6.  
  7. import { build } from "esbuild"
  8.  
  9. import * as path from "path"
  10.  
  11. export function buildScript(scriptList: string[]): Plugin { 
  12.  
  13. const _scriptList = scriptList.map((src) => path.resolve(src)); 
  14.  
  15. async function buildScript(src: string) { 
  16.  
  17. await build({ 
  18.  
  19. entryPoints: [src], 
  20.  
  21. outfile: src.slice(0, src.length - 2) + "js"
  22.  
  23. format: "iife"
  24.  
  25. bundle: true
  26.  
  27. platform: "browser"
  28.  
  29. sourcemap: "inline"
  30.  
  31. allowOverwrite: true
  32.  
  33. }); 
  34.  
  35. console.log("構建完成: ", path.relative(path.resolve(), src)); 
  36.  
  37.  
  38. return { 
  39.  
  40. name: "vite-plugin-build-script"
  41.  
  42. async configureServer(server) { 
  43.  
  44. server.watcher.add(_scriptList); 
  45.  
  46. const scriptSet = new Set(_scriptList); 
  47.  
  48. server.watcher.on("change", (filePath) => { 
  49.  
  50. // console.log('change: ', filePath) 
  51.  
  52. if (scriptSet.has(filePath)) { 
  53.  
  54. buildScript(filePath); 
  55.  
  56.  
  57. }); 
  58.  
  59. }, 
  60.  
  61. async buildStart() { 
  62.  
  63. // console.log('buildStart: ', this.meta.watchMode) 
  64.  
  65. if (this.meta.watchMode) { 
  66.  
  67. _scriptList.forEach((src) => this.addWatchFile(src)); 
  68.  
  69.  
  70. await Promise.all(_scriptList.map(buildScript)); 
  71.  
  72. }, 
  73.  
  74. }; 
  75.  
  76.  
  77. // https://vitejs.dev/config/ 
  78.  
  79. export default defineConfig({ 
  80.  
  81. plugins: [ 
  82.  
  83. reactRefresh(), 
  84.  
  85. checker({ typescript: true }), 
  86.  
  87. buildScript([path.resolve("src/utils/app/whitelistWorkerGlobalScope.ts")]), 
  88.  
  89. ], 
  90.  
  91. }); 

現在,我們可以看到 web worker 中的全局 api 只有白名單中的那些了。

1635097498575

web worker 沙箱的主要優勢

  • 可以直接使用 chrome devtool 調試
  • 直接支持 console/setTimeout/setInterval api
  • 直接支持消息通信的 api

 

責任編輯:張燕妮 來源: rxliuli blog
相關推薦

2021-12-29 11:38:59

JS前端沙箱

2015-11-12 10:03:34

前端H5web

2016-09-06 21:37:41

2021-04-09 08:51:32

Web WorkerJavaScript微前端

2025-06-12 08:52:18

WebWorkerJSAPI

2017-07-17 06:46:06

2011-05-25 10:21:44

Javascript

2025-03-24 07:15:00

WebWorkerWeb瀏覽器

2025-09-17 18:09:40

WebWorker頁面單線程

2024-03-12 08:44:56

WebWorkerTypeScript語法

2022-04-13 09:28:19

JavaScripiframe開發

2025-07-23 07:16:17

JavaScript隔離開發

2019-02-13 14:58:43

cssjavascript前端

2025-05-29 09:02:27

2025-09-30 09:28:04

JavaScript開發代碼

2025-02-20 12:11:07

WebWorker場景JS

2019-03-22 08:25:47

沙箱網絡安全惡意軟件

2010-09-15 09:03:44

JavaScript

2021-12-29 22:29:10

JavaScript前端數組

2010-08-11 13:46:01

Flex安全沙箱
點贊
收藏

51CTO技術棧公眾號

国产综合色产| 久久久久毛片| 2022国产精品视频| 日本乱人伦a精品| 日韩女同一区二区三区| 免费成人黄色网| 一区二区在线看| 蜜桃精品久久久久久久免费影院 | 国产日韩欧美综合| 免费中文字幕视频| 国产一区二区三区四区五区| 91精品国产品国语在线不卡| 91av视频在线| 亚洲最大成人网站| 亚洲精品777| 亚洲国产cao| 色综合影院在线观看| 国产男男gay网站| 99精品国产一区二区青青牛奶 | 1024国产在线| 成人精品亚洲人成在线| 国产精品劲爆视频| 国产精品成人aaaa在线| 日本精品黄色| 亚洲福利影片在线| 国产高清999| 电影一区二区三| 亚洲欧美另类小说视频| 欧美下载看逼逼| 亚洲福利在线观看视频| 日本伊人精品一区二区三区观看方式| 欧美激情伊人电影| 超薄肉色丝袜一二三| 成人在线超碰| 8x福利精品第一导航| 日本在线观看a| 男女视频在线| 亚洲欧美在线视频观看| 日韩在线三区| 精品人妻aV中文字幕乱码色欲| 日韩电影免费在线看| 午夜精品一区二区三区视频免费看| 美女网站视频色| 国产精品免费不| 日韩精品极品视频| 美女黄色一级视频| 日本一区精品视频| 欧美精品1区2区| 婷婷六月天在线| 欧美大片1688| 福利精品视频在线| 国产伦精品一区二区三区四区视频_| 成人片在线看| 亚洲天堂久久久久久久| 亚洲国产午夜伦理片大全在线观看网站 | 99精彩视频| 99视频在线观看免费| 蜜桃久久av一区| 国产精品精品久久久| 91porny九色| 丝袜美腿亚洲综合| 国产成人鲁鲁免费视频a| 综合网在线观看| 亚洲欧美久久| 国产ts一区二区| 欧产日产国产69| 久久亚洲国产精品一区二区| 日本高清+成人网在线观看| 日韩成人免费在线观看| 亚洲色诱最新| 51久久精品夜色国产麻豆| 五月婷婷开心网| 国产欧美激情| 日本精品中文字幕| 欧美男人天堂网| 美国一区二区三区在线播放 | 久久久影院官网| 欧美乱偷一区二区三区在线| 搞黄视频免费在线观看| 国产精品国产自产拍高清av王其| 制服诱惑一区| 国产在线xxx| 欧美性色19p| 五月婷婷丁香色| 国模大尺度视频一区二区| 日韩一区二区麻豆国产| 国产一级黄色录像| 国产亚洲一区| 麻豆国产va免费精品高清在线| 国产福利久久久| 丝袜美腿亚洲色图| 亚洲综合色激情五月| 午夜黄色小视频| 国产精品另类一区| 日韩久久久久久久久久久久| 色偷偷偷在线视频播放 | 性色av蜜臀av| 2019国产精品| 天天做天天爱天天高潮| 麻豆mv在线看| 欧美日韩视频在线观看一区二区三区 | 免费观看亚洲视频大全| 精品久久久久99| 黄色a一级视频| 欧美在线色图| 麻豆成人在线看| 在线观看成人毛片| 视频一区欧美日韩| 亚洲一区久久久| 天天干天天爱天天操| 国产亚洲欧美日韩在线一区| 一本一生久久a久久精品综合蜜| 国产成人无吗| 午夜不卡av在线| 国产麻花豆剧传媒精品mv在线| 91国产精品| 日韩精品在线免费| 亚洲视频重口味| 99视频一区| 国产精品爽爽ⅴa在线观看| 国产又粗又猛又黄又爽| caoporen国产精品视频| 日韩福利影院| 涩涩视频网站在线观看| 在线成人午夜影院| 黄色性生活一级片| 久久久国产精品| 97婷婷大伊香蕉精品视频| 在线视频 中文字幕| 成人午夜电影久久影院| 日本一区不卡| 小视频免费在线观看| 91精品国产综合久久久久久漫画| 亚洲国产精品无码久久久久高潮| 日韩美女一区二区三区在线观看| 高清一区二区三区四区五区| 最近中文字幕免费观看| av中文字幕一区| 亚洲不卡1区| 99riav视频在线观看| 欧美日本一区二区在线观看| 色天使在线视频| 欧美暴力喷水在线| 国产精品美女免费看| 午夜精品无码一区二区三区| 国产精品免费视频网站| 国产精品久久久久9999爆乳| 麻豆精品一区| 久久精品免费播放| japanese国产在线观看| 2021久久国产精品不只是精品| 久久久久99精品成人片| 996久久国产精品线观看| 色婷婷av一区二区三区在线观看 | 午夜大片在线观看| 欧美视频免费| 国产精品国产三级国产aⅴ9色| 香蕉视频网站在线| 日韩欧美中文字幕在线播放| 天天躁日日躁狠狠躁免费麻豆| 一区二区日韩欧美| 成人精品久久av网站| 在线视频婷婷| 欧美亚洲综合一区| 中文字幕 自拍| 久久精品理论片| 亚洲国产精品久久久久婷婷老年 | 综合色中文字幕| 污污视频网站免费观看| 日韩精品久久久久久久电影99爱| 日韩免费不卡av| 肉丝一区二区| 欧美日韩免费看| av网站有哪些| 美女诱惑黄网站一区| 久久99精品久久久久久久青青日本| 好看的中文字幕在线播放| 精品欧美一区二区三区精品久久| 91九色丨porny丨极品女神| 免费成人av在线播放| 一区二区三区四区欧美| 91精品亚洲一区在线观看| 最近更新的2019中文字幕| 中文字幕高清在线免费播放| 国产精品不卡一区二区三区| 一区二区三区国产好的精华液| 亚洲啊v在线观看| 97免费资源站| 丁香花在线影院| 精品偷拍一区二区三区在线看| 久久免费在线观看视频| 久久夜色精品一区| 69久久久久久| 911久久香蕉国产线看观看| 亚洲一区二区三区毛片| 欧美1—12sexvideos| 日韩黄色av网站| 日韩三级一区二区| 一区二区在线观看免费| 亚洲av熟女高潮一区二区| 香蕉视频成人在线观看| 欧美一区二区福利| 五月天色综合| 久久久久久久一区二区| 男生女生差差差的视频在线观看| 欧美一级理论性理论a| 日本少妇bbwbbw精品| 久久蜜臀中文字幕| 亚洲男人天堂2021| 亚洲无线视频| 日韩精品伦理第一区| 欧美日韩午夜电影网| 8090成年在线看片午夜| aa在线视频| 日韩精品视频在线观看免费| 中文在线a天堂| 依依成人综合视频| 人人爽人人爽人人片| 国产精品99久久久久| 欧美牲交a欧美牲交| 91九色精品国产一区二区| 国偷自产av一区二区三区小尤奈| 日本精品另类| 久久人人看视频| 国产黄色在线观看| 亚洲精品国产精品自产a区红杏吧 亚洲精品国产精品乱码不99按摩 亚洲精品国产精品久久清纯直播 亚洲精品国产精品国自产在线 | 欧美日韩在线精品一区二区三区| 欧美成人免费全部网站| 高清欧美性猛交xxxx| 在线免费观看黄| 亚洲精品视频中文字幕| 可以免费观看的毛片| 欧美丰满美乳xxx高潮www| 9i看片成人免费看片| 一区二区在线电影| 欧美乱大交做爰xxxⅹ小说| 99久久精品免费看国产免费软件| www.偷拍.com| 日本成人在线一区| 久久精品免费一区二区| 欧美日韩三级| 亚洲欧洲三级| 色爱av综合网| 91麻豆国产精品| 亚州欧美在线| 国产精品旅馆在线| www.com.cn成人| 久久全国免费视频| 日本大片在线播放| 亚洲天堂免费观看| 国内三级在线观看| 精品视频久久久久久久| 亚洲国产精品二区| 欧美一区二区日韩一区二区| 中文字幕久久久久| 精品国产老师黑色丝袜高跟鞋| 国产香蕉在线视频| 亚洲综合色视频| 免费在线观看黄色av| 亚洲日本青草视频在线怡红院 | 日本一级黄视频| 欧美女激情福利| 400部精品国偷自产在线观看| 热久久天天拍国产| 日韩欧美第二区在线观看| 亚洲警察之高压线| 久久艳妇乳肉豪妇荡乳av| 久久99国内| 日韩激情久久| 精品国产一区二区三区久久久樱花 | 久久视频国产| 色一情一区二区三区四区| 国产精品tv| 精品国产乱码久久久久久丨区2区 精品国产乱码久久久久久蜜柚 | 亚洲韩国青草视频| 色偷偷在线观看| 亚洲精品国产免费| 四虎影视在线播放| 亚洲第一av在线| 国产高清在线观看| 日韩在线免费av| 欧美三级电影一区二区三区| 久久五月情影视| 宅男网站在线免费观看| 久久久久久久久久久免费| 里番在线播放| 26uuu亚洲伊人春色| 成人av观看| 国产精品视频一区国模私拍| 岛国一区二区| 91丨九色丨国产| 精品三级国产| 欧洲久久久久久| 久久成人综合| 免费的av在线| 夜夜嗨一区二区三区| 欧在线一二三四区| 日韩精品欧美精品| 久久无码专区国产精品s| 91丨porny丨蝌蚪视频| 欧美精品日韩在线| 亚洲视频1区2区| 欧美一二三区视频| 欧美午夜影院一区| 免费国产羞羞网站视频| 亚洲女人被黑人巨大进入al| 日韩在线资源| 国内精品免费午夜毛片| 日日夜夜天天综合| 99理论电影网| 日韩伦理一区| 鲁一鲁一鲁一鲁一澡| 美女视频黄频大全不卡视频在线播放| 亚洲高清av一区二区三区| 91在线免费视频观看| 黄色a级片在线观看| 在线日韩av片| 亚洲成人第一区| 国产一区二区美女视频| 青青在线视频| 国产精品露脸av在线| 成人知道污网站| 久久久成人精品一区二区三区| 国产欧美精品| 国产91在线免费观看| 久久精子c满五个校花| 国精品无码一区二区三区| 欧美日韩国产精品一区| 亚洲女同志亚洲女同女播放| 国产一区二区三区精品久久久| 久久亚洲导航| 亚洲qvod图片区电影| 九九精品在线| 日韩精品一区二区三区不卡| 国产精品自拍在线| 中文字幕有码在线播放| 欧美日韩国产激情| 成人免费一级视频| 色偷偷88888欧美精品久久久| 9999在线视频| 91理论片午午论夜理片久久| 国模精品一区| 欧美一区二区三区爽大粗免费| 激情国产一区二区| 法国空姐电影在线观看| 午夜av一区二区| 韩国av永久免费| 欧美成人免费在线视频| 激情久久一区二区| 亚洲精品在线免费| 日韩成人免费电影| 老鸭窝一区二区| 午夜精品在线看| 国产熟女精品视频| 色综合导航网站| 精品三级国产| 欧美做受777cos| 精品无人区卡一卡二卡三乱码免费卡| 精品无码人妻一区| 91电影在线观看| 欧美在线观看在线观看| 97超碰色婷婷| 网红女主播少妇精品视频| 国产一线二线三线女| 成人av动漫在线| 日本一区二区三区四区五区| 亚洲成年网站在线观看| 999av小视频在线| 欧美一区二区三区电影在线观看| 另类激情亚洲| 性欧美一区二区| 欧美日韩一区精品| 久久av少妇| 国产日韩在线精品av| 99久久婷婷国产综合精品电影√| 五月天婷婷亚洲| 中文字幕佐山爱一区二区免费| 99精品免费观看| 欧美黑人国产人伦爽爽爽| 欧美wwwwww| 韩国日本在线视频| www国产精品av| 伊人影院中文字幕| 不卡毛片在线看| a看欧美黄色女同性恋| av免费观看国产| 久久夜色精品一区| 一级黄色片免费| 久精品免费视频| 精品国产影院| 无码中文字幕色专区| 国产精品成人网| 成人小说亚洲一区二区三区| 97在线视频一区| 国产在视频线精品视频www666| 亚洲三级在线视频| 一本一本大道香蕉久在线精品 | 男女男精品网站| 久久国产高清视频| 欧美成人一区二区三区片免费|