微前端是如何实现作用域隔离的?

微前端是如何实现作用域隔离的?


111

一、前言

沙箱(Sandbox)是一种安全机制,目的是让程序运行在一个相对独立的隔离环境,使其不对外界的程序造成影响,保障系统的安全。作为开发人员,我们经常会同沙箱环境打交道,例如,服务器中使用 Docker 创建应用容器;使用 Codesandbox运行 Demo示例;在程序中创建沙箱执行动态脚本等。

二、使用场景

2.1 iPaaS 可视化 API 编排  

在流程编排的某些节点需要用到低代码模型转换(Transformer),用户可在转换器流程节点自定义 Groovy 脚本实现,服务端在执行自定义的 Groovy 脚本时,会放置在沙箱中,避免对整个流程逻辑造成影响。

2.2 微前端应用沙箱  

在微前端当中,有一些全局对象在所有的应用中需要共享,如 Window 对象。不同开发团队的子应用很难通过规范约束他们使用全局变量。为了保证应用的可靠性,需要技术手段去治理运行时的冲突问题;通过使用沙箱,每个前端应用都可以拥有自己的上下文环境、页面路由和状态管理,而不会相互干扰或冲突。

接下来的篇章我们将介绍大前端领域沙箱的实现以及我们如何基于JS沙箱落地应用的过程。

三、JS沙箱调研

3.1 eval和Function  

前端常见的动态执行代码的方式是使用 Eval 和 New Function 提供一个运行外部代码的环境:     

// 使用 eval 的糟糕代码:
function looseJsonParse(obj){
    return eval(`(${obj})`);
}
console.log(looseJsonParse(
   "{a:(4-1), b:function(){}, c:new Date()}"
))

// 使用 Function 的更好的代码:
function looseJsonParse(obj){
    return Function(`"use strict";return (${obj})`)();
}
console.log(looseJsonParse(
   "{a:(4-1), b:function(){}, c:new Date()}"
))

两种方式都可以正常执行,并且返回结果相同,但是用来创建沙箱环境还不够格,因为它们都能访问[全局变量],无法实现作用域隔离。

3.2 with + new Function + proxy实现  

3.2.1 with关键字  

JavaScript 在查找某个未使用命名空间的变量时,会通过作用于链来查找,而 with 关键字,可以使得查找时,先从该对象的属性开始查找,若该对象没有要查找的属性,顺着上一级作用域链查找,若不存在要查到的属性,则会返回 ReferenceError 异常。

不推荐使用 with,在 ECMAScript 5 严格模式中该标签已被禁止。推荐的替代方案是声明一个临时变量来承载你所需要的属性。

3.2.2 ES6 Proxy  

Proxy 是 ES6 提供的新语法,Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。示例如下:

const handler = {
  get: function (obj, prop) {
    return prop in obj ? obj[prop] : 'weimob';
  },
};

const p = new Proxy({}, handler);
p.a = 2023;
p.b = undefined;

console.log(p.a, p.b); // 2023 undefined
console.log('c' in p, p.c); // false, weimob    

3.2.3 Symbol.unScopables  

With 再加上 Proxy 几乎完美解决 JS 沙箱机制。但是如果对象的Symbol.unScopables设置为 true ,会无视 with 的作用域直接向上查找,造成沙箱逃逸,所以要另外处理 Symbol.unScopables。

3.2.4 沙箱实现   

function sandbox(code, context) {
  context = context || Object.create(null);
  const fn = new Function('context', `with(context){return (${code})}`);
  const proxy = new Proxy(context, {
    has(target, key) {
      if (["console", "setTimeout", "Date"].includes(key)) {
        return true
      }
      if (!target.hasOwnProperty(key)) {
        throw new Error(`Illegal operation for key ${key}`)
      }
      return target[key]
    },
    get(target, key, receiver) {
      if (key === Symbol.unscopables) {
        return undefined;
      }
      return Reflect.get(target, key, receiver);
    }
  })
  return fn.call(proxy, proxy);
}

sandbox('3+2') // 5
sandbox('console.log("智慧商业服务商")') // Cannot read property 'log' of undefined
sandbox('console.log("智慧商业服务商")', {console: window.console}) // 智慧商业服务商
       

上面的代码主要做了3件事,实现沙箱隔离:

  • 使用 with API,将对象添加到作用域链的顶部,变量访问会优先查找你传入的参数对象,之后再往上找;
  • 通过ES6提供的proxy,设置has函数,实现对象的访问拦截,同时处理Symbol.unscopables 的属性,控制可以被访问的变量 context,阻断沙箱内的对外访问;
  • 绑定 this 指向 proxy 对象,防止 this 访问 window;

3.3 基于iframe实现  

iframe 标签可以创造一个独立的浏览器原生级别的运行环境,这个环境由浏览器实现了与主环境的隔离。在 iframe 中运行的脚本程序访问到的全局对象均是当前 iframe 执行上下文提供的,不会影响其父页面的主体功能,因此使用 iframe 来实现一个沙箱是目前最方便、简单、安全的方法。

const parent = window;
const frame = document.createElement('iframe');
// 限制代码 iframe 代码执行能力
frame.sandbox = 'allow-same-origin';
document.body.appendChild(iframe);
const sandboxGlobal = iframe.contentWindow;

3.4 node运行时实现  

3.4.1 原生模块vm  

相较于浏览器环境,Node运行时就简单很多,使用其提供的原生vm模块,可以很方便的创建V8虚拟机,并在指定上下文编译和执行代码;

const vm = require('node:vm');

const x = 1;

const context = { x: 2 };
vm.createContext(context); // Contextify the object.

const code = 'x += 40; var y = 17;';
vm.runInContext(code, context);

console.log(context.x); // 42
console.log(context.y); // 17

console.log(x); // 1; y is not defined.

问题来了,使用 vm.runInContext 看似创建了沙箱隔离环境,但 vm 模块足够安全吗?引用 Node 官网的回答

node:vm 模块不是安全机制。不要用它来运行不受信任的代码。

3.4.2 不安全原因  

为什么不是安全机制,继续剖析;

const vm = require('vm');
vm.runInNewContext('this.constructor.constructor("return process")().exit()');
console.log('智慧商业服务商') // 永远不会执行

这就是 JS 语言的特性,以上示例中 runInNewContext 会默认创建上下文对象, this 指向默认创建的 ctx 对象 并通过原型链的方式拿到沙盒外的 Funtion,通过Function 访问全局变量,完成逃逸,并执行逃逸后的 JS 代码。

3.4.3 解决方案  

解决方案是绑定上下文对象,同时切断上下文对象的原型链,提供纯净的上下文对象,避免通过原型链逃逸。

const vm = require('vm');
let sandBox = Object.create(null);
sandBox.title = '智慧商业服务商'
sandBox.console = console
vm.runInNewContext('console.log(title)', sandBox);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/571617.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

03-JAVA设计模式-访问者模式

访问者模式 什么是访问者模式 访问者模式(Visitor Pattern)是软件设计模式中的一种行为模式,它用于将数据结构中的元素与操作这些元素的操作解耦。这种模式使得可以在不修改数据结构的情况下添加新的操作。 在访问者模式中,我们…

PHP+MYSQL多条件选一通用搜索系统功能单文件7KB

通用功能: 快速填写参数用于自己的mysql数据表搜索,ajax载入数据 <?php header("content-Type: text/html; charsetUTF-8"); //error_reporting(0);$dbhost "localhost"; //数据库地址本地localhost $dbuser "chalidecom"; //数据库账号 …

Tkinter是什么?

Tkinter是Python标准库中的一个模块&#xff0c;用于创建图形用户界面&#xff08;GUI&#xff09;应用程序。它提供了一组工具和组件&#xff0c;使开发者能够在Python中创建窗口、按钮、标签、文本框、菜单等各种界面元素&#xff0c;并通过这些元素构建交互式的用户界面。 T…

稀碎从零算法笔记Day59-LeetCode: 感染二叉树需要的总时间

题型&#xff1a;树、图、BFS、DFS 链接&#xff1a;2385. 感染二叉树需要的总时间 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 给你一棵二叉树的根节点 root &#xff0c;二叉树中节点的值 互不相同 。另给你一个整数 start 。在第 0 分钟…

Three.js入门学习笔记

学习资料&#xff1a; 【Three.js】Three.js快速上手教程_three.module.js-CSDN博客 2024年了&#xff0c;是该学学Three.js了_three.js 2024-CSDN博客 一、three.js简介 three.js是JavaScript编写的WebGL第三方库。 three.js&#xff0c;webGL&#xff0c;openGL三者的关…

微信小程序4~6章总结

目录 第四章 页面组件总结 4.1 组件的定义及属性 4.2 容器视图组件 4.2.1 view 4.2.2 scroll-view 4.2.3 swiper 4.3 基础内容组件 4.3.1 icon ​编辑 4.3.2 text 4.3.3 progress ​编辑 4.4 表单组件 4.4.1 button 4.4.2 radio 4.4.3 checkbox 4.4.4 switch …

第27天:安全开发-PHP应用TP框架路由访问对象操作内置过滤绕过核心漏洞

第二十七天 一、TP框架-开发-路由访问&数据库&文件上传&MVC模型 1.TP框架-开发-配置架构&路由&MVC模型 参考&#xff1a;https://www.kancloud.cn/manual/thinkphp5_1 配置架构-导入使用路由访问-URL访问数据库操作-应用对象文件上传操作-应用对象前端页…

51.HarmonyOS鸿蒙系统 App(ArkUI)通知

普通文本通知测试 长文本通知测试 多行文本通知测试 图片通知测试 进度条通知测试 通知简介 应用可以通过通知接口发送通知消息&#xff0c;终端用户可以通过通知栏查看通知内容&#xff0c;也可以点击通知来打开应用。 通知常见的使用场景&#xff1a; 显示接收到的短消息、…

L1-099 帮助色盲 - java

L1-099 帮助色盲 代码长度限制 16 KB 时间限制 400 ms 内存限制 64 MB 栈限制 8192 KB 题目描述&#xff1a; 在古老的红绿灯面前&#xff0c;红绿色盲患者无法分辨当前亮起的灯是红色还是绿色&#xff0c;有些聪明人通过路口的策略是这样的&#xff1a;当红灯或绿灯亮起时&am…

VMware-Linux切换桥接模式上网教程(超详细)

这里写目录标题 1. 虚拟机关机2. VMware 虚拟网络配置2.1 检查是否存在 VMnet02.2 修改桥接模式2.3 修改Linux虚拟机网络适配器 3. Linux 系统配置3.1 修改系统网卡配置3.1.1 配置项含义解释3.1.2 查看物理机网络信息3.3.3 修改配置 3.2 重启服务 4. 测试网络连接情况5. 注意事…

数据可视化-ECharts Html项目实战(14)

在之前的文章中&#xff0c;我们深入学习ECharts鼠标左键触发。想了解的朋友可以查看这篇文章。同时&#xff0c;希望我的文章能帮助到你&#xff0c;如果觉得我的文章写的不错&#xff0c;请留下你宝贵的点赞&#xff0c;谢谢。 数据可视化-ECharts Html项目实战&#xff08;…

目标检测——YOLOv7算法解读

论文&#xff1a;YOLOv7: Trainable bag-of-freebies sets new state-of-the-art for real-time object detectors (2022.7.6) 作者&#xff1a;Chien-Yao Wang, Alexey Bochkovskiy, Hong-Yuan Mark Liao 链接&#xff1a;https://arxiv.org/abs/2207.02696 代码&#xff1a;h…

Bayes判别示例数据:鸢尾花数据集

使用Bayes判别的R语言实例通常涉及使用朴素贝叶斯分类器。朴素贝叶斯分类器是一种简单的概率分类器&#xff0c;基于贝叶斯定理和特征之间的独立性假设。在R中&#xff0c;我们可以使用e1071包中的naiveBayes函数来实现这一算法。下面&#xff0c;我将通过一个简单的示例展示如…

vue 实现左侧导航栏,右侧锚点定位滚动到指定位置(超简单方法)

项目截图&#xff1a; 实现方法&#xff1a; 点击左侧菜单根据元素id定位到可视内容区域。 浏览器原生提供了一种方法scrollIntoView 。 通过scrollIntoView方法可以把元素滚动到可视区域内。 behavior: "smooth"是指定滚动方式为平滑效果。 具体代码如下&#xf…

Flink CDC详解

文章目录 Flink CDC一 CDC简介1.1 CDC定义1.2 CDC应用场景1.3 CDC实现机制1.4 开源CDC工具对比 二 Flink CDC简介2.1 Flink CDC介绍2.2 Flink CDC Connector(连接器)2.3 Flink CDC && Flink版本2.4 Flink CDC特点 三 Flink CDC发展3.1 发展历程3.2 背景Dynamic Table &…

微软发布Phi-3 Mini,性能媲美GPT-3.5、Llama-3,可在手机端运行

前言 微软发布了最新版的Phi系列小型语言模型(SLM) - Phi-3。这个系列包括3个不同参数规模的版本&#xff1a;Phi-3 Mini (38亿参数)、Phi-3 Small (70亿参数)和Phi-3 Medium (140亿参数)。 Phi系列模型是微软研究团队开发的小规模参数语言模型。从第一代Phi-1到第二代Phi-2&…

深度学习中的熵、交叉熵、相对熵(KL散度)、极大释然估计之间的联系与区别

熵的最初来源于热力学。在热力学中&#xff0c;熵代表了系统的无序程度或混乱程度&#xff0c;也可以理解为系统的热力学状态的一种度量。后来被广泛引用于各个领域中&#xff0c;如信息学、统计学、AI等&#xff0c;甚至社会学当中。接下来将大家领略一下深度学习中熵的应用。…

【高阶数据结构】B树 {B树的概念;B树的实现:节点设计,查找,插入,遍历,删除;B树的性能分析;B+树和B*树;B树的应用}

一、常见的搜索结构 以上结构适合用于数据量相对不是很大&#xff0c;能够一次性存放在内存中&#xff0c;进行数据查找的场景。如果数据量很大&#xff0c;比如有100G数据&#xff0c;无法一次放进内存中&#xff0c;那就只能放在磁盘上了&#xff0c;如果放在磁盘上&#xff…

短视频素材哪里有?8个视频素材免费下载素材库无水印

在这个视觉内容至关重要的时代&#xff0c;每一位视频创作者都需要接触到多样化和高质量的视频素材&#xff0c;以提升作品的吸引力和专业度。以下这些视频素材网站将为你提供从全球各地收集的丰富资源。 1. 蛙学府&#xff08;中国&#xff09; 着重提供有关中国文化和场景的…

黑盒优化系列(一):自动化提示词优化【一、绪论】

大语言模型的提示词 随着ChatGPT等大语言模型的问世&#xff0c;我们获取知识的方式从单一的搜索引擎如Google转变为类似ChatGPT这种通过 Q & A 方式提供的方法。 我们尝试对比一下不同提示词&#xff0c;对应的模型输出 ChatGPT无提示词 API&#xff1a; ChatGPT 3.5 …