您当前的位置:首页 > 网站建设 > javascript
| php | asp | css | H5 | javascript | Mysql | Dreamweaver | Delphi | 网站维护 | 帝国cms | React | 考试系统 | ajax | jQuery | 小程序 |

浅谈 JavaScript 沙箱Sandbox

51自学网 2022-02-21 13:38:43
  javascript

前言:

说到沙箱,我们的脑海中可能会条件反射地联想到上面这个画面并瞬间变得兴致满满,不过很可惜本文并不涉及“我的世界”(老封面党了),下文将逐步介绍“浏览器世界”的沙箱。

1、什么是沙箱

在计算机安全中, 沙箱(Sandbox)是一种用于隔离正在运行程序的安全机制 ,通常用于执行未经测试或不受信任的程序或代码,它会 为待执行的程序创建一个独立的执行环境,内部程序的执行不会影响到外部程序的运行 。

例如,下列场景就涉及了沙箱这一抽象的概念:

  • 我们开发的页面程序运行在浏览器中,程序只能修改浏览器允许我们修改的那部分接口,我们无法通过这段脚本影响到浏览器之外的状态,在这个场景下浏览器本身就是一个沙箱。
  • 浏览器中每个标签页运行一个独立的网页,每个标签页之间互不影响,这个标签页就是一个沙箱。
  • ......

2、沙箱有什么应用场景

上述介绍了一些较为宏观的沙箱场景,其实在日常的开发中也存在很多的场景需要应用这样一个机制:

  • 执行 JSONP 请求回来的字符串时或引入不知名第三方 JS 库时,可能需要创造一个沙箱来执行这些代码。
  • Vue 模板表达式的计算是运行在一个沙盒之中的,在模板字符串中的表达式只能获取部分全局对象,这一点官方文档有提到,这一点官方文档有提到,详情可参阅源码

  • 在线代码编辑器,如 CodeSanbox 等在线代码编辑器在执行脚本时都会将程序放置在一个沙箱中,防止程序访问/影响主页面。
  • 许多应用程序提供了插件(Plugin)机制,开发者可以书写自己的插件程序实现某些自定义功能。开发过插件的同学应该知道开发插件时会有很多限制条件,这些应用程序在运行插件时需要遵循宿主程序制定的运行规则,插件的运行环境和规则就是一个沙箱。例如下图是 Figma 插件的运行机制:

总而言之,只要遇到不可信的第三方代码,我们就可以使用沙箱将代码进行隔离,从而保障外部程序的稳定运行。如果不做任何处理地执行不可信代码,在前端中最直观的副作用/危害就是污染、篡改全局 window 状态,影响主页面功能甚至被 XSS 攻击。

// 子应用代码window.location.href = 'www.diaoyu.com'Object.prototype.toString = () => {    console.log('You are a fool :)')  }document.querySelectorAll('div').forEach(node => node.classList.add('hhh'))sendRequest(document.cookie)...

3、如何实现一个 JS 沙箱

要实现一个沙箱,其实就是去制定一套程序执行机制,在这套机制的作用下 沙箱内部程序的运行不会影响到外部程序的运行 。

3.1 最简陋的沙箱

要实现这样一个效果,最直接的想法就是程序中访问的 所有变量均来自可靠或自主实现的上下文环境而不会从全局的执行环境中取值, 那么要实现变量的访问均来自一个可靠上下文环境,

我们需要为待执行程序构造一个作用域:

// 执行上下文对象const ctx =     func: variable => {        console.log(variable)    },    foo: 'foo'}// 最简陋的沙箱function poorestSandbox(code, ctx) {    eval(code) // 为执行程序构造了一个函数作用域}// 待执行程序const code = `    ctx.foo = 'bar'    ctx.func(ctx.foo)`poorestSandbox(code, ctx) // bar

这样的一个沙箱要求源程序在获取任意变量时都要加上执行上下文对象的前缀,这显然是非常不合理的,因为我们没有办法控制第三方的行为,是否有办法去掉这个前缀呢?

3.2 非常简陋的沙箱(With)

使用 with声明可以帮我们去掉这个前缀, with 会在作用域链的顶端添加一个新的作用域,该作用域的变量对象会加入 with 传入的对象,因此相较于外部环境其内部的代码在查找变量时会优先在该对象上进行查找。

// 执行上下文对象const ctx = {    func: variable => {        console.log(variable)    },    foo: 'foo'}// 非常简陋的沙箱function veryPoorSandbox(code, ctx) {    with(ctx) { // Add with        eval(code)    }}// 待执行程序const code = `    foo = 'bar'    func(foo)`veryPoorSandbox(code, ctx) // bar

这样一来就 实现了执行程序中的变量在沙箱提供的上下文环境中查找先于外部执行环境 的效果。

问题来了,在提供的上下文对象中没有找到某个变量时,代码仍会沿着作用域链一层一层向上查找,这样的一个沙箱仍然无法控制内部代码的执行。我们 希望沙箱中的代码只在手动提供的上下文对象中查找变量,如果上下文对象中不存在该变量则直接报错或返回 undefined

3.3 没那么简陋的沙箱(With + Proxy)

为了解决上述抛出的问题,我们借助 ES2015 的一个新特性
下载地址:
jquery使用canvas标签绘制验证码
jquery canvas绘制图片验证码实例

万事OK自学网:51自学网_软件自学网_CAD自学网自学excel、自学PS、自学CAD、自学C语言、自学css3实例,是一个通过网络自主学习工作技能的自学平台,网友喜欢的软件自学网站。