腾讯一面:你了解js的沙箱环境吗?

去年的面试了,最近复盘了一下,发现菜的一批,有些问题一下子就答出来了,现在答的话,那时候还在瞎鸡儿答我也不知道答的什么。。。。

在 JavaScript 中,沙箱(sandbox)是一个安全机制,用于隔离运行代码,以防止代码对其它部分的应用程序或系统造成不必要的影响或安全风险。沙箱提供了一个受控环境,在这个环境中,代码可以被执行而不影响外部环境,从而保护用户数据和系统安全。

在浏览器中,沙箱通常指的是浏览器为每个标签页提供的隔离环境。这种隔离保证了一个标签页中的 JavaScript 代码无法访问另一个标签页中的内容,除非两个页面遵循同源策略(即协议、域名和端口号都相同)或者通过 CORS(跨源资源共享)明确允许了跨源访问。网页 web 代码内容必须通过 IPC 通道才能与浏览器内核进程通信,通信过程会进行安全的检查。沙箱设计的目的是为了让不可信的代码运行在一定的环境中,从而限制这些代码访问隔离区之外的资源。

js 中沙箱的使用场景有什么

在 JavaScript 中,沙箱通常用于隔离和控制代码执行的环境,以确保代码运行在一个安全的、受限制的环境中,避免对主环境造成潜在的损害。

  1. 执行第三方 js:当你有必要执行第三方 js 的时候,而这份 js 文件又不一定可信的时候;

  2. 在线代码编辑器:相信大家都有使用过一些在线代码编辑器,而这些代码的执行,基本都会放置在沙箱中,防止对页面本身造成影响;

  3. Web 应用安全: 在浏览器中运行来自不同来源的 JavaScript 代码时,沙箱可以限制这些代码的权限,防止恶意代码访问敏感资源或执行危险操作。

  4. 插件和第三方脚本: 当 Web 应用需要加载和执行第三方插件或脚本时,通过沙箱可以限制这些脚本的访问权限,保护主应用的安全和数据。

  5. jsonp:解析服务器所返回的 jsonp 请求时,如果不信任 jsonp 中的数据,可以通过创建沙箱的方式来解析获取数据;

jsonp 通信机制

JSONP 的工作原理就是通过利用 <script> 标签没有跨域限制的“漏洞”(历史遗迹啊)来达到与第三方通讯的目的。当需要通讯时,本站脚本创建一个 <script> 元素,地址指向第三方的 API 网址,形如:

<script src="http://www.example.net/api?param1=1&param2=2"></script>

并提供一个回调函数来接收数据(函数名可约定,或通过地址参数传递)。 第三方产生的响应为 json 数据的包装(故称之为 jsonp,即 json padding),形如: callback({"name":"hax","gender":"Male"}) 这样浏览器会调用 callback 函数,并传递解析后 json 对象作为参数。本站脚本可在 callback 函数里处理所传入的数据。

下面是如何通过创建沙箱环境来解析 JSONP 数据的基本思路:

  1. 创建独立的 iframe 作为沙箱:通过在主页面中动态创建一个 iframe,可以为 JSONP 请求提供一个隔离的执行环境。这个 iframe 没有访问主页面 DOM 的权限,从而限制了其中执行的代码对主页面可能造成的影响。

  2. 在 iframe 中发起 JSONP 请求:将 JSONP 请求的 <script> 标签插入到上述创建的 iframe 中,这样由 JSONP 请求返回的脚本就会在这个隔离的环境中执行。这意味着,即使返回的脚本中包含恶意代码,其影响也被限制在了 iframe 中,不会波及到主页面。

  3. 安全地从 iframe 中获取数据:虽然 iframe 中的脚本不能直接修改主页面的 DOM,但它仍然可以通过预定的方式(如通过 postMessage API)安全地将数据传递给主页面。主页面需要设置事件监听器来接收这些数据,并确保通过验证数据来源等措施来保证数据的安全性。

  4. 限制和监控 iframe 中的行为:进一步增强安全性的措施包括使用 Content Security Policy (CSP)来限制 iframe 中可以加载和执行的资源,以及使用其他浏览器安全特性来监控和控制 iframe 中的行为。

通过以上步骤,即使 JSONP 响应中包含不可信的数据或代码,其潜在的危害也可以被有效地隔离和控制,从而保护了用户的数据和安全。

总而言之,当你要解析或执行不可信的 JS 的时候,当你要隔离被执行代码的执行环境的时候,当你要对执行代码中可访问对象进行限制的时候,沙箱就派上用场了。

with + new Function 实现沙箱

在 JavaScript 中,使用 with 语句和 new Function 可以创建一个简单的沙箱环境。这种方式可以限制代码运行时的作用域,防止它访问全局变量或执行不安全的操作。

在 with 的块级作用域下,变量访问会优先查找你传入的参数对象,之后再往上找,所以相当于你变相监控到了代码中的变量访问:

function createSandbox(code) {
  // 创建一个空对象,用作沙箱环境中的全局对象
  const sandbox = {};
  // 使用with语句将代码的作用域设置为这个空对象
  // 使用new Function创建一个新的函数,限制代码访问外部作用域,只能访问sandbox内的变量和函数
  const script = new Function("sandbox", `with(sandbox) { ${code} }`);
  // 执行这个函数,并传入sandbox作为参数
  return function () {
    script(sandbox);
  };
}

// 使用沙箱环境
const sandboxedScript = createSandbox(
  'console.log("Hello from the sandbox!"); var x = 10;'
);
sandboxedScript(); // 输出: Hello from the sandbox!
console.log(typeof x); // 输出: undefined,因为x是在沙箱内部定义的,外部访问不到

定义了一个 createSandbox 函数,它接受一个字符串 code 作为参数,这个字符串是要在沙箱环境中执行的代码。我们首先创建一个空对象 sandbox,这个对象将作为沙箱的全局对象。然后,我们使用 with(sandbox)语句将沙箱中的代码执行环境设置为这个空对象,这意味着代码中所有的变量和函数定义都将局限在这个空对象内,无法访问外部的全局对象和变量。

new Function 构造函数创建一个新的函数,它执行传入的代码字符串。通过这种方式,我们能够动态执行代码,同时限制这段代码的作用域,防止它访问或修改沙箱外部的环境。最后,我们返回一个闭包函数,这个函数在被调用时会执行沙箱中的代码。

需要注意的是,虽然这种方法可以在一定程度上隔离执行环境,但它并不是完全安全的。with 和 new Function 都有一些安全隐患,特别是如果沙箱中执行的代码可以访问到 Function 构造器本身,它就可能绕过沙箱限制,执行任意代码。可见,new Function + with 的这种沙箱方式,防君子不防小人。

iframe 实现沙箱

使用 iframe 创建沙箱环境是 Web 开发中常见的一种技术,它允许你在当前页面内嵌套一个完全独立的 HTML 页面。这种方法可以有效隔离 JavaScript 执行环境,防止脚本访问主页面的 DOM 或 JavaScript 环境,从而提高安全性。以下是如何使用 iframe 来实现沙箱环境的一个详细代码示例:

首先我们需要编写 HTML 结构:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <iframe id="sandbox" style="display: none"></iframe>

    <script src="index.js"></script>
  </body>
</html>

我们再在 index.js,在 js 代码中,通过操作这个 iframe 的 contentWindow 属性来实现一个简单的沙箱环境。这里的思路是向 iframe 注入脚本并执行,这样执行的脚本就在 iframe 的独立环境中运行,与主页面隔离:

// index.js
function createSandbox(callback) {
  const iframe = document.getElementById("sandbox");
  if (!iframe) {
    return console.error("沙箱iframe未找到");
  }

  // 确保iframe完全加载后再执行代码
  iframe.onload = function () {
    const iframeWindow = iframe.contentWindow;

    // 在沙箱环境中定义一些安全的全局变量或函数,如果需要的话
    iframeWindow.safeGlobalVar = {
      /* 安全的数据或方法 */
    };

    // 执行回调函数,传入沙箱的window对象,以便在其中执行代码
    callback(iframeWindow);
  };

  // 重新加载iframe以确保环境清洁
  iframe.src = "about:blank";
}

// 使用沙箱
createSandbox(function (sandboxWindow) {
  // 在沙箱环境中执行代码
  sandboxWindow.eval('console.log("Hello from the sandbox!");');
});

在上面的这些代码中,createSandbox 函数接收一个回调函数作为参数,该回调函数会在 iframe 加载完成后执行。在回调函数中,我们可以通过 iframe 的 contentWindow 属性来访问并操作 iframe 内的全局对象,包括定义全局变量、函数或者通过 eval 执行一些 JavaScript 代码。

但是这些也会带来一下限制:

  1. script 脚本不能执行

  2. 不能发送 ajax 请求

  3. 不能使用本地存储,即 localStorage,cookie 等

  4. 不能创建新的弹窗和 window

  5. 不能发送表单

  6. 不能加载额外插件比如 flash 等

但是别担心,为了进一步提高安全性,HTML5 引入了 sandbox 属性,它可以限制 iframe 中代码的能力。sandbox 属性可以采用以下值:

  1. allow-scripts: 允许执行脚本。

  2. allow-same-origin: 允许与包含文档同源的文档交互。

  3. allow-forms: 允许表单提交。

  4. allow-popups: 允许弹窗,比如通过 window.open 方法。

  5. allow-top-navigation: 允许通过链接导航到顶级框架。

使用 sandbox 属性的 iframe 示例:

<iframe src="sandbox.html" sandbox="allow-scripts" id="sandbox"></iframe>

接下来我们结合 postMessage API,将你需要执行的代码,和需要暴露的数据传递过去,然后和我们的 iframe 页面通信就行了。

首先,在主页面中,我们需要获取 iframe 的引用并使用 postMessage 方法发送消息。消息可以是任何可序列化的对象。

<!DOCTYPE html>
<html>
  <head>
    <title>主页面</title>
  </head>
  <body>
    <iframe
      src="./sandbox.html"
      id="sandbox"
      style="width: 600px; height: 400px"
    ></iframe>

    <script>
      var iframe = document.getElementById("sandbox");

      // 等待iframe加载完成
      iframe.onload = function () {
        // 向iframe发送消息
        var targetOrigin = "http://127.0.0.1:5500/"; // 替换为iframe的实际源
        iframe.contentWindow.postMessage("Hello, sandbox!", targetOrigin);
      };

      // 监听来自iframe的消息
      window.addEventListener("message", function (event) {
        // 检查消息来源是否符合预期

        if (event.origin !== "http://127.0.0.1:5500") {
          return; // 来源不匹配时忽略消息
        }

        // 处理接收到的消息
        console.log("Received message from iframe:", event.data);
      });
    </script>
  </body>
</html>

postMessage 的第一个参数是要发送的消息,第二个参数是接收消息页面的源(origin),这是一个安全特性,以确保消息只被发送到指定的来源页面。

在 iframe 页面中,我们需要监听 message 事件来接收主页面发送过来的信息:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      window.addEventListener("message", function (event) {
        // 检查消息来源是否符合预期

        if (event.origin !== "http://127.0.0.1:5500") {
          return; // 来源不匹配时忽略消息
        }

        // 处理接收到的消息
        console.log("Received message:", event.data);

        // 回复消息给主页面
        event.source.postMessage("Hello, main page!", event.origin);
      });
    </script>
  </body>
</html>

在使用 postMessage 进行通信时,始终要检查 event.origin,并且在发送消息时指定精确的目标 origin,这样可以防止潜在的安全问题。通过这种方式,即使在跨域的情况下,主页面与 iframe 或新窗口之间也能安全、有效地进行数据交换。

20240315220045

Web Workers 实现沙箱

使用 Web Workers 作为沙箱的方法,通过动态创建一个 Blob 对象来包含你想在 Worker 中执行的 JavaScript 代码,然后使用这个 Blob 对象创建一个 Worker。这种方式的好处是它允许你动态地执行任意的 JavaScript 代码,同时确保这些代码在一个与主页面环境隔离的 Worker 中运行,提供了一种隔离执行代码的手段。

function workerSandbox(appCode) {
  var blob = new Blob([appCode]);
  var appWorker = new Worker(window.URL.createObjectURL(blob));
}

workerSandbox("const a = 1;console.log(a);"); // 输出1

console.log(a); // a not defined

这种使用 Web Workers 实现沙箱的方法为在 Web 应用中隔离和执行 JavaScript 代码提供了一种有力的手段,特别适合那些需要保持 UI 响应性而又要执行复杂或潜在风险代码的场景。

总结

JavaScript 的沙箱环境是一种隔离执行环境,允许运行和测试代码而不干扰主应用程序的状态或数据。它通过限制代码访问全局变量和函数,提供了一个安全的方式来执行不信任的代码,避免潜在的安全风险和数据泄露。沙箱环境对于保护应用程序免受恶意代码或不确定性代码影响至关重要。

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

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

相关文章

【python】Paste Mask

学习来自【OpenCv】利用roi 掩模 将一张图片添加到另一张上 任务描述&#xff1a;提取图片A的 mask 区域&#xff0c;并粘贴到图片B上 文章目录 1 代码实现2 结果展示3 涉及到的库cv2.bitwise_notcv2.bitwise_andcv2.add 附录——获取 mask 的边界框 1 代码实现 A 图 A 图的 …

linux中/etc/hosts文件的内容和功能

更准确的说是主机和ip地址映射绑定配置文件 用于主机名解析成ip地址的 转换配置 效果&#xff1a; 这个东西是局域网下面的解析&#xff0c;老师说是本地局域网解析 windows对应的就是

腾讯云APP备案指南:一站式完成备案手续,助您顺利上线

工信部最新通知要求所有互联网信息服务提供者完成移动互联网应用程序备案手续。腾讯云为开发者提供了简单易行的备案流程&#xff0c;本文详细解答如何在腾讯云平台完成备案&#xff0c;帮助开发者快速上线自己的APP。从验证备案域名到腾讯云审核&#xff0c;一步步指导您完成备…

6. DAX 时间函数-- DATE 日期--FIRSTDATE \LASTDATE\DATESMTD\DATESQTD\DATESYTD

函数名目的语法返回值FIRSTDATE 返回指定日期列在当前上下文中的第一个非空日期。FIRSTDATE ( <日期列> )表 包含具有日期值的单列和单行的表。LASTDATE返回指定日期列在当前上下文中的最后一个非空日期。LASTDATE ( <日期列> )表 包含具有日期值的单列和单行的表。…

首批!18个“人工智能+高等教育”应用场景典型案例

近日&#xff0c;教育部发布通知&#xff0c;公布了首批18个“人工智能高等教育”应用场景典型案例—— 为深入贯彻落实国家关于开展“人工智能”行动的战略部署&#xff0c;积极推动高等教育与人工智能技术的融合发展&#xff0c;利用智能技术支撑人才培养模式的创新、教学方…

150个 HTML5 成体系的网站模版 量大慢选 持续更新中

目录 HTML5 网站模版 No.1HTML5 网站模版 No.2HTML5 网站模版 No.3HTML5 网站模版 No.4HTML5 网站模版 No.5 HTML5 网站模版 No.1 HTML5 网站模版 No.1 HTML5 网站模版 No.2 HTML5 网站模版 No.2 HTML5 网站模版 No.3 HTML5 成体系网站模版 No.3 HTML5 网站模版…

上海晋名室外气瓶暂存柜海盐项目落地

上周海盐县人民医院武原分院的SAVEST室外气瓶暂存柜项目成功交付验收&#xff0c;此次项目主要用于医院气瓶等室外暂存安全。 用户单位在日常工作运营中涉及到氧气瓶、杜瓦罐等室外安全储存问题&#xff0c;用户在寻找解决方案的过程中搜索到上海晋名的室外气瓶暂存柜系列后挺感…

什么是反向 ETL?为什么它很有价值?

提取、转换、加载 &#xff08;ETL&#xff09; 过程已经成熟并被广泛采用。 它只涉及从各种源系统中获取数据&#xff0c;将其转换为标准化数据模型&#xff0c;然后将其加载到数据仓库中。从那里&#xff0c;您的团队使用其商业智能 &#xff08;BI&#xff09; 和分析工具中…

57、通过EEG数据的SHAPE变化,揭开EEG-TCNet的黑匣子[看好了小子,我只教这一次]

之前在第18篇博客中对于EEG-TCNet这个处理EEG信号的sota模型进行了介绍&#xff0c;也给出了模型&#xff0c;目前也是全网对于EEG-TCNet浏览度最高的文章了&#xff0c;我觉得讲的已经很细致了&#xff0c;没想到还是有不少同学疑问&#xff0c;这也是全网缺少该模型pytorch代…

13、ESP32 深度睡眠

1、深度睡眠 ESP32 可以在不同的电源模式之间切换&#xff1a; 活动模式调制解调器睡眠模式浅睡眠模式深度睡眠模式休眠模式 在深度睡眠模式下&#xff0c;CPU 或 Wi-Fi 活动都不会发生&#xff0c;但超低功耗 &#xff08;ULP&#xff09; 协处理器仍可打开电源&#xff0c;R…

常见的数据结构

链表 链表&#xff1a;适用于插入删除多、读少的场景。 链表在新增、删除数据都比较容易&#xff0c;可以在 O(1) 的时间复杂度内完成。 但对于查找&#xff0c;不管是按照位置的查找还是按照数值条件的查找&#xff0c;都需要对全部数据进行遍历。这显然就是 O(n) 的时间复杂…

解锁流量密码:如何利用HubSpot打造高效的获客策略?(下)

在当今数字化时代&#xff0c;流量是企业成功的关键。HubSpot作为一款全面的营销自动化工具&#xff0c;为我们提供了强大的支持&#xff0c;帮助企业打造高效的流量获取策略。接下来&#xff0c;我们将从社交媒体与SEO优化、自动化营销流程、数据分析与效果评估以及流量获取策…

畅通工程(并查集)

//新生训练 #include <iostream> #include <algorithm> #include <bits/stdc.h> using namespace std;#define N 1010int fa[N];int Find(int x) {if (x ! fa[x]){fa[x] Find(fa[x]);}return fa[x]; }void Union(int x, int y) {int a Find(x);int b Find…

Linux读写文件

前言 学习了文件系统&#xff0c;就能理解为什么说Linux下一切皆文件。 语言层面的操作 在c语言的学习中我们可以使用fopen()函数对文件进行操作。 int main() {//FILE * fp fopen("./log.txt", "w");//FILE * fp fopen("./log.txt", "…

Compose 布局

文章目录 Compose 布局ColumnColumn属性使用 RowRow属性使用 BoxBox属性使用 ConstraintLayoutLazyColumnLazyColumn属性使用使用多类型使用粘性标题回到顶部 LazyRowLazyRow属性使用 LazyVerticalGridLazyVerticalGrid属性使用 Compose 布局 Column Compose中的”垂直线性布…

BlueNRG-X 原理图参数说明

1. 前言 为了让客户在原理图设计阶段少走弯路&#xff0c;我这里结合客户评估和设计阶段常遇到的问题&#xff0c;整理了一下 BlueNRG-1/-2 相关设计及注意事项以备客户解惑用。 2. BlueNRG-1/-2 的原理图参数说明及设计注意事项 2.1. BlueNRG-1/-2 原理图及参数如下&#x…

NFTScan | 04.08~04.14 NFT 市场热点汇总

欢迎来到由 NFT 基础设施 NFTScan 出品的 NFT 生态热点事件每周汇总。 周期&#xff1a;2024.04.08~ 2024.04.14 NFT Hot News 01/ 数据&#xff1a;Runestone 地板价突破 0.07 BTC&#xff0c;创历史新高 4 月 8 日&#xff0c;据数据显示&#xff0c;Runestone 地板价突破 …

【第七届openGauss技术文章征集】 openGauss新版本征文活动来啦!

活动背景 2024年3月30日&#xff0c;openGauss 6.0.0版本正式上线&#xff0c;该版本与之前版本特性功能保持兼容&#xff0c;在内核能力、DataPod三层资源池化架构、DataKit数据全生命周期管理平台、生态兼容性等方面全面增强。&#xff08;下方【点击原文】即可查看更多【新…

Android--ConnectivityManager使用

一、前言 Android10之后官方废弃了通过WifiManager连接WIFI的方式&#xff0c;现在要使用ConnectivityManager连接WIFI 二、连接WIFI public class MainActivity extends AppCompatActivity {private static final String TAG"lkx";Overrideprotected void onCrea…

【黑马头条】-day10热点文章定时计算-xxl-job

文章目录 1 今日内容1.1 需求分析1.2 解决方案1.3 定时计算1.4 定时任务方案对比 2 分布式任务调度3 xxl-job3.1 简介3.2 环境搭建3.2.1 配置maven3.2.2 源码说明 3.3 配置部署调度中心3.3.1 运行sql脚本3.3.2 修改配置application.properties3.3.3 启动引导类 3.4 docker配置x…