怎样平安的运转第三方javascript代码(下) | 申博官网
登录
  • 欢迎进入申博官网!
  • 如果您觉得申博官网对你有帮助,那么赶紧使用Ctrl+D 收藏申博官网并分享出去吧
  • 这里是申博官方网!
  • 申博官网是菲律宾sunbet官网品牌平台!
  • 申博开户专业品牌平台!

怎样平安的运转第三方javascript代码(下)

申博_新闻事件 申博 24次浏览 未收录 0个评论

运用Realms平安地完成API

总的来讲,我们以为Realms的沙箱功用照样非常不错的。只管与JavaScript诠释器要领比拟,我们要处置惩罚更多的细节,但它依然可以作为白名单而不是黑名单来运作,这使其完成代码越发紧凑,因而也更便于审计。作为另一个加分项,它照样由受人尊重的Web社区成员所建立的。

然则,单靠Realms依然没法满足我们的要求,由于它只是一个沙箱,插件在个中不能做任何事情。我们依然须要完成可以供插件运用的API。这些API也必需是平安的,由于大多数插件都须要可以显现一些UI,以及发送收集要求。

比方,假定沙箱默许状态下不包含console对象。毕竟,console是一个浏览器API,而不是JavaScript功用。为此,我们可以将其作为全局变量通报给沙箱。

realm.evaluate(USER_CODE, { log: console.log })

或许将本来的值隐藏在函数中,以致沙箱没法修正它们:

realm.evaluate(USER_CODE, { log: (...args) => { console.log(...args) } })

不幸的是,这是一个平安漏洞。纵然在第二个示例中,匿名函数也是在realm以外建立的,却直接提供给了realm。这意味着插件可以经由过程log函数的原型链逃逸到沙箱以外。

完成console.log的准确要领是将其封装到在realm内部建立的函数中。这里是一个简化版本的示例(https://github.com/tc39/proposition-realms/issues/189)(实际上,它还须要对realms间抛出非常举行响应的转换处置惩罚)。

// Create a factory function in the target realm.
// The factory return a new function holding a closure.
const safeLogFactory = realm.evaluate(
        (function safeLogFactory(unsafeLog) {
                return function safeLog(...args) {
                        unsafeLog(...args);
                }
        })
);
 
// Create a safe function
const safeLog = safeLogFactory(console.log);
 
// Test it, abort if unsafe
const outerIntrinsics = safeLog instanceof Function;
const innerIntrinsics = realm.evaluate(log instanceof Function, { log: safeLog });
if (outerIntrinsics || !innerIntrinsics) throw new TypeError();
 
// Use it
realm.evaluate(log("Hello outside world!"), { log: safeLog });

一般来讲,不许可沙箱直接接见在沙箱以外建立的对象,由于这些对象可以接见全局作用域。一样主要的是,运用编程接口在操纵沙箱内部的对象时要分外警惕,由于这能够跟沙箱外部的对象相殽杂。

这就带来了一个题目——虽然该要领可以用于构建一个平安的运用程序接口,然则开辟人员每次向运用程序接口增加一个新函数时,都须要考核对象的源在语义上是不是存在题目。那我们该怎样处理呢?

用于诠释器的API

题目是直接应用Realms构建Figma运用编程接口的话,则须要对每一个API端点都都举行平安审计,包含其输入和输出值。很明显,如许的话,事情量着实太大了。

怎样平安的运转第三方javascript代码(下)

 

只管Realms沙箱中的代码是运用雷同的JavaScript引擎运转的,但假如假定我们依然面对WebAssembly要领所带来的限定的话,关于我们来讲黑白常有协助的。

回忆一下Duktape,在尝试#2章节中,JavaScript诠释器将被编译为WebAssembly。因而,主线程中的JavaScript代码没法直接保留对沙箱内对象的援用。毕竟,在沙箱中,WebAssembly是经由过程自身来治理堆的,因而,一切JavaScript对象都位于这个堆地点的内存空间中。事实上,Duktape以至能够没有运用与浏览器引擎雷同的内存示意来完成JavaScript对象!

因而,Duktape的API只能借助于初级操纵完成,比方一会儿将整数和字符串复制到虚拟机中,一会儿再复制返来。即使可以在诠释器中保留对象或函数的援用,但也仅能作为不透明句柄运用。

这类接口看起来像下面如许:

// vm == virtual machine == interpreter
export interface LowLevelJavascriptVm {
  typeof(handle: VmHandle): string
 
  getNumber(handle: VmHandle): number
  getString(handle: VmHandle): string
 
  newNumber(value: number): VmHandle
  newString(value: string): VmHandle
  newObject(prototype?: VmHandle): VmHandle
  newFunction(name: string, value: (this: VmHandle, ...args: VmHandle[]) => VmHandle): VmHandle
 
  // For accessing properties of objects
  getProp(handle: VmHandle, key: string | VmHandle): VmHandle
  setProp(handle: VmHandle, key: string | VmHandle, value: VmHandle): void
  defineProp(handle: VmHandle, key: string | VmHandle, descriptor: VmPropertyDescriptor): void
 
  callFunction(func: VmHandle, thisVal: VmHandle, ...args: VmHandle[]): VmCallResult
  evalCode(code: string): VmCallResult
}
 
export interface VmPropertyDescriptor {
  configurable?: boolean
  enumerable?: boolean
  get?: (this: VmHandle) => VmHandle
  set?: (this: VmHandle, value: VmHandle) => void
}

请注意,这些就是API完成将要运用的接口,但它或多或少地以一对一的情势映射到Duktape的诠释器API。毕竟,Duktape(和相似的虚拟机)的构建恰是为了以嵌入情势运用,并许可嵌入方与Duktape举行通讯。

Microsoft Teams可被用来执行任意payload

Microsoft Teams是一款基于聊天的智能团队协作工具,可以同步进行文档共享,并为成员提供包括语音、视频会议在内的即时通讯工具。攻击者可以用Microsoft Teams的mock installation文件夹中的真实二进制文件来执行恶意payload。 该问题影响大多数使用Squirrel安装和更新框架的Windows桌面APP,该开使用NuGet包。研究人员测试发现受影响的应用包括WhatsApp, Grammarly, GitHub, Slack 和 Discord。 易构建包 逆向工程师Reegun Richard发现他可以创建一个伪造的Microsoft Teams包,并使用

运用该接口,可以将对象{x: 10, y: 10}通报到沙箱,详细以下所示:

let vm: LowLevelJavascriptVm = createVm()
let jsVector = { x: 10, y: 10 }
let vmVector = vm.createObject()
vm.setProp(vmVector, "x", vm.newNumber(jsVector.x))
vm.setProp(vmVector, "y", vm.newNumber(jsVector.y))

下面给出用于Figma节点对象的“opacity”属性的API:

vm.defineProp(vmNodePrototype, 'opacity', {
  enumerable: true,
  get: function(this: VmHandle) {
    return vm.newNumber(getNode(vm, this).opacity)
  },
  set: function(this: VmHandle, val: VmHandle) {
    getNode(vm, this).opacity = vm.getNumber(val)
    return vm.undefined
  }
})

这个底层接口可以经由过程Realms沙箱很好地完成。如许的完成只须要相对较少的代码(就本例来讲,大约为500 LOC)。不过,我们须要对这一小部分代码举行细致审计。然则,一旦完成了上述事情,就可以直接应用这些接口来开辟其他的API,而不必忧郁沙箱方面的平安题目。

怎样平安的运转第三方javascript代码(下)

从本质上讲,这就是将JavaScript诠释器和Realms沙箱视为“运转JavaScript代码的一些自力环境”。

在沙箱上建立初级笼统还须要关注另一个关键题目。虽然我们对Realms的平安性充满了自信心,但依据履历,在平安方面再警惕也不为过。所以,我们无妨假定Realms中存在未知的平安漏洞,总有一天会变成我们必需处置惩罚的题目。这就是前面花了很多章节来引见怎样编译一个以至不必的诠释器的缘由。由于该API是经由过程一个其完成可以交换的接口完成的,所以,诠释器依然是一个有用的备份设想,我们可以在无需从新完成任何API或损坏任何现有插件的状态下启用它。

插件功用的多样性

如今,我们获得了可以平安运转恣意插件的沙箱,以及许可这些插件操纵Figma文档的API。这就相当于为我们的天下打开了一扇大门。

然则,我们试图处理的最初题目是为设想东西构建插件体系。为了提高可用性,这些插件中的大部分都须要具有建立用户界面的功用,而且很多插件还须要具有某种情势的收集接见才能。更一般地说,我们愿望插件可以尽量多地应用浏览器和JavaScript的生态体系。

我们可以一次一个地、警惕谨慎地公然平安的、受限定的浏览器API版本,就像上面的console.log示例一样。但是,浏览器API(尤其是DOM)的涉及面太大,以至比JavaScript自身还要大。这类尝试能够因限定太多而没法运用,或许能够存在平安缺点。

我们经由过程从新引入源为null的<inline-iframe>来处理这个题目。如许的话,插件就可以建立一个<inline-iframe>并在个中安排恣意HTML和Javascript代码了。

怎样平安的运转第三方javascript代码(下)

这跟我们最初尝试运用的<inline-iframe>的区分在于,如今,插件是由两个组件构成:

· 一个可以接见Figma文档并在Realms沙箱内的主线程上运转的组件。

· 一个可以接见浏览器API并在<inline-iframe>内部运转的组件。

这两个组件可以经由过程音讯通报举行通讯。虽然这类架构使得运用浏览器API比在统一环境中运转这两个组件要烦琐一些,然则,鉴于现在的浏览器手艺的状态,这是平安地运转别人Javascript代码的最好手艺,固然,跟着手艺的提高,未来一定会涌现更好的插件建立手艺。

小结

经由一段迂回的探索之旅后,我们终究找到了一个完成插件的卓有成效的处理计划。借助于Realm的shim库,我们不仅完成了第三方代码的断绝,同时依然许可它在开辟人员熟习的类浏览器环境中运转。

虽然这对我们来讲是最好的处理计划,但关于每一个公司或平台而言,它能够并不是终究之选。假如您须要断绝第三方代码,而且具有与我们雷同的机能和API人体工程学方面的要求,那末我们的处理计划照样非常值得自创的;不然的话,能够直接经由过程iframe断绝代码就足够了,而且简朴的计划老是上上之选。固然,我们的起点也是冲着简朴去的!

本文翻译自:https://www.figma.com/blog/how-we-built-the-figma-plugin-system/


申博|网络安全巴士站声明:该文看法仅代表作者自己,与本平台无关。版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明怎样平安的运转第三方javascript代码(下)
喜欢 (0)
[]
分享 (0)
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址