整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

仅仅过去 4 年,微软最终放弃了 Electron

软近期宣布,旗下 Teams 应用活跃用户已经达到惊人的 2.5 亿。这让 Teams 成了继 Word 和 Excel 之后,微软 Office 生产力套件中的又一位当红明星。然而,Teams 一直受到性能问题的困扰,疯狂吞噬系统资源,用户们对此吐槽不断。

前不久,微软 Teams 高级副总裁宣布,Teams 将放弃 Electron,转而匹配微软自己的 Edge WebView2 渲染引擎以寻求性能提升。官方声称,调整之后 Teams 的内存消耗量将直接减半,并有望以 Teams 2.0 的形象随 2022 年末上市的 Windows 11 一同亮相。

据悉,在 Windows 11 中,用户可以通过文字、聊天、语音或视频与联系人即时连接,无论他们使用的是 Windows、Android 还是 iOS。对方即使没有下载 Teams 应用程序,双方也可以通过双向短信联系。Windows 11 还支持立即静音和取消静音,或者直接从任务栏开始呈现 Teams。

追求更低的内存占用

对于已经尝试了许多不同技术来减少桌面客户端所需内存的微软来说,这似乎是迈出的很大一步了。有很多网友表示很开心看到这一变化。

“Angular 也不见了。我们现在 100% 使用 reactjs。”Teams 工程师 Rish Tandon 在推特上表示。“这些变化听起来很棒!”有人留言道,但对于网友提出的“Win10 和 MacOs 也会有吗?”Tandon 没有回答。

根据 Tandon 的说法,这项工作大概花费了 Teams 团队 6 个月的时间,优化后的 Teams 2.0 消耗的内存将只有 Teams 1.0 上相同帐户的一半。

时至今日,仍有众多知名应用都选用 Electron 来提供支持。Electron 框架能够帮助 Web 开发者将自己的 Web 应用发布至桌面平台,且不受任何特定平台的复杂性影响。但由于一切 Electron 应用程序后端都要运行只属于自己的 Chrome OS 实例,所以同时运行两个以上此类应用就会疯狂消耗主机资源。

于是,在 Electron 之上执行大量处理操作的 Teams 也无法避免地疯狂占用内存、拖慢计算机速度。微软甚至专门发布了文档页面,解释为什么 Teams 的内存占用量如此之高。

与 Electron 不同,WebView2 会监控 Chromium 的行为、检测还有多少系统内存可用,从而更有效地利用内存资源优化渲染体验。如果其他应用程序或服务需要系统内存,Chromium 就会将空间移交给这些进程。如此一来,内存容量较小的低端计算机也能带来不错的性能表现。

WebView2 更像是一种类似于应用窗口的控件,专门用于渲染 Web 页面。事实上,WebView2 控件还允许在原生应用程序中嵌入 Web 技术(包括 HTML、CSS 与 JavaScript)。所以要想将 Teams 规模的应用程序过渡至 WebView2,开发团队需要对大量由 Electron 提供的抽象进行重写。因此,Teams 在本质上将变得更接近于原生 Windows 应用程序。

目前,WebView2 已经被 Outlook 作为微软“One Outlook”项目的组成部分。

为什么选 Webview2 ?

Teams 需要处理大量音频与视频内容,所以微软认为最好能把一部分工作负载转移给 WebView2 更擅长的原生形式。事实也证明,Electron 抽象并不能有效完成这些处理任务。但从严格意义上来说,Webview2 并不属于 Electron 的替代方案。

Webview2 并不是 Electron 那样可以在桌面平台上快速发布 Web 应用的打包器。Electron 与 WebView2 都是以 Chromium 为基础构建而成,但更严格地说,WebView2 继承的是 Edge 源代码,而 Edge 又用到了 Chromium 源代码的一个分支。Electron 则不与 Chrome 共享任何 DLL。WebView2 二进制文件硬链接至 Edge(截至 Edge 90 的 Stable 版本),所以二者使用着相同的磁盘及其他一些工作集机制。

Electron 应用会始终捆绑并分发其开发过程中所使用的特定 Electron 版本。相比之下,WebView2 在发布方面则提供两个选项:可以直接捆绑应用开发时所使用的特定 WebView2 库,也可以使用系统上已经存在的共享运行时版本。WebView2 为这两种方法分别提供工具,包括一个防止共享运行时丢失的引导安装程序。而且从 Windows 11 版本开始,操作系统已经内置有 WebView2 运行时。

捆绑二者框架的应用程序负责保持框架更新,包括更新各次要安全增强版本。而对于使用共享 WebView2 运行时的应用程序,版本维护则依靠 WebView2 自己的更新程序,会以类似 Chrome 或 Edge 的方式独立于应用程序之外运行。WebView2 更新应用程序的代码或任何其他依赖项仍由开发者负责管理,这一点与 Electron 相同。值得注意的是,Windows 更新管理功能并未覆盖到 Electron 与 WebView2。

Electron 与 WebView2 都继承了 Chromium 的多进程架构——即由单一主进程同一个或多个渲染器进程通信。这些进程同系统上正在运行的其他应用程序完全分离,每个 Electron 应用程序都拥有一个独立的进程树,其中包含一个根浏览器进程、部分实用程序进程外加一定数量的渲染进程。与应用套件类似,使用相同用户数据文件夹的各 WebView2 应用程序之间会共享非渲染器进程,但使用不同数据文件夹的 WebView2 应用程序之间则不共享任何进程。

ElectronJS 流程模型:

基于 WebView2 的应用程序流程模型:

Electron 能够为各类常见桌面应用需求提供 API,例如菜单、文件系统访问、通知等等。WebView2 则能以组件的形式集成到 WinForms、WPF、WinUI 或者 Win32 等应用程序框架当中。另外,WebView2 仅通过 JavaScript 提供符合 Web 标准的操作系统 API。

Electron 当中集成有 Node.js,因此 Electron 应用程序可以使用来自渲染器及主进程的任何 Node.js API、模块或者 node-native-addon。WebView2 应用程序则不会对应用程序各个部分所使用的编程语言或框架做任何预设,JavaScript 代码必须通过 application-host 进程代理才能访问操作系统。

Electron 提供可配置的 Web 内容安全模型,配置范围涵盖完全开放访问到完全沙箱模式。WebView2 内容则始终保持沙箱化。Electron 还提供关于如何选择安全模式的详尽说明文档,而 WebView2 则提供丰富的安全最佳实践。

Electron 源代码在 GitHub 上进行维护与交付,各应用程序能够修改并构建属于自己的 Electron 品牌。WebView2 源代码则并未登陆 GitHub。

具体差异总结如下:

Electron

WebView2

构建基础

Chromium

Edge

源代码是否登陆GitHub

是否共享Edge/Chrome DLL

是(截至Edge 90)

不同应用程序间是否共享运行时

可选

应用程序API

Node.js

沙箱

可选

始终

需要应用程序框架

所支持平台

Mac, Win, Linux

Win (Mac/Linux正在筹备)

不同应用间是否共享进程

从不

可选

框架更新由谁管理

应用程序

WebView2

性能差异有多大?

需要强调一点区别,这也是 Electron 应用程序中的一项重要性能考量因素。

在 Chromium 当中,浏览器进程负责充当沙箱渲染器与系统其余部分之间的 IPC 代理。虽然 Electron 支持非沙箱渲染进程,但也有不少应用会选择启用沙箱以提升安全水平。WebView2 则始终启用沙箱,所以对于大多数 Electron 及 WebView2 应用程序而言,IPC 确实会影响到整体性能。

虽然 Electron 与 WebView2 的流程模型基本相似,但底层 IPC 却有所不同。JavaScript 与 C++或 C#之间的通信需要经过编组,而且最常见的方法是编组为 JSON 字符串。请注意,JSON 序列化/解析操作的资源成本极高,因此 IPC 瓶颈必然会对性能产生负面影响。因此从 Edge 93 开始,WebView2 将对网络事件使用 CBOR。

Electron 则通过 MessagePorts API 支持任意两个进程之间的直接 IPC,其中使用到了结构化克隆算法。利用这项功能,应用程序就能避免在不同进程间发送对象时执行资源成本高昂的 JSON 序列化操作。

Electron 与 WebView2 虽然有着不少差异之处,但二者在渲染 Webn 内容方面却高度一致。最核心的影响还是来自应用程序架构与 JavaScript 库/框架在内存与性能层面的影响,毕竟同样师出 Chromium。

2017 年时,Electron 可以说是 Web 应用在桌面平台发布的最佳、甚至是唯一选项,但如今它却成了需要被优化淘汰的对象。这可能代表着跨平台框架格局中的一大关键里程碑,也可能仅仅是微软 Teams 做出的一项小小调整。但具体如何,还有待时间的检验。

相关链接:

https://www.electronjs.org/blog/webview2

https://blog.devgenius.io/microsoft-is-finally-ditching-electron-9e081757f9db

lectron是一个前端桌面开发框架,对于前端开发人员来说是个很好的选择,做过前端的都懂的,HTML、CSS、Javascript都烂熟于心,可以很方便地利用这个框架开发跨平台的桌面应用。

Electron官方文档是这样解释的:

Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium 和 Node.js 到 二进制的 Electron 允许您保持一个 JavaScript 代码代码库并创建 在Windows上运行的跨平台应用 macOS和Linux——不需要本地开发 经验。

一、开发环境的搭建(Windows环境学习)

1、安装node.js,官网(nodejs.org)下载 LTS(长期更新维护)版本安装即可。

2、测试是否安装成功。开始--运行--"cmd",在命令提示符窗口输入:node -v ,npm -v,正常出现版本号即告安装成功。

3、安装Electron框架。同样在命令提示符窗口输入: npm install -g electron ,执行全局安装。也可以进行开发环境安装,即在项目下进行安装,命令是:npm install electron --save-dev。这个过程比较慢,国外的网站,要看时间段或者线路等,用单位的中国电信专线是比较快,在家中用移动和联通的聚合线路(用的软路由)也还算可以,如果慢的不能忍受,就多开几个窗口同时搞吧!!!安装完成后用命令:npx electron -v 检测出现版本号即为安装正常。

4、都安装完成后,执行命令:electron。如果安装的没有问题,正常情况下会弹出一个Electron框架程序窗口,即宣布Electron开发环境搭建大功告成,下一步就可以进行开发测试了......

1 简介

在今年Blackhat的会议上,安全研究员Aaditya Purani和Max GarreG分享了议题《Pwning Popular Desktop apps while uncovering new attack surface on Electron》, 分享了几个Electron利用的新方法和他们挖到几个Electron应用的漏洞案例。


Electron是一个桌面应用程序的框架,极大的方便了跨平台应用的开发。Chromium和Node JS是Electron的重要组成部分。因为Electron拥有直接执行Nodejs代码的能力,并且内置了Chromium内核。一个XSS漏洞,很可能就会导致RCE。


本文以安全研究员Aaditya Purani和Max GarreG的思路为依据,简单聊一聊Electron结构,上下文进行和Electron框架XSS到RCE的攻击面。


02 Electron基本构架

Electron是使用JavaScript,HTML和CSS构建跨平台的桌面应用程序的框架,可构建出兼容Mac、Windows和Linux三个平台的应用程序。


Electron使用Chromium完成UI渲染, 通过内置Node.js提供原生系统的能力,如文件系统和网络的访问。


Electron继承了来自Chromium的多进程架构,每个Electron应用都有一个单一的主进程,作为应用程序的入口点。主进程在、Node.js环境中运行,这意味着它具有require模块和使用所有Node.js API的能力。主进程的主要目标是使用BrowserWindow模块创建和管理应用程序窗口。


每个Electron应用都会为每个打开的BrowserWindow( 与每个网页嵌入 ) 生成一个单独的渲染器进程。渲染器负责渲染网页内容。渲染器进程也有访问NodeJs共享库的能力,但是需要依赖系统配置。


渲染器进程和主进程直接存在隔离,通过进程IPC进行通信,一般我们通过XSS拿到的JS执行权限处于渲染进程之中。


渲染进程的上下文也可以分为两种:

Preload.js和网页上下文,preload的上下文访问权限,一般高于网页上下文 。


这时有两种思路获取权限:

利用渲染进程本身进行RCE

  • 通过NodeJs共享库RCE
  • 通过chromium Nday RCE

通过IPC,影响主进程进行RCE

  • 需要主进程ipcmain,实现了危险方法
  • 需要当前执行上下文可以访问IPC


03 Electron核心选项

而我们可以使用哪种思路,还需取决于Electron选项,以下几个是值得我们关注的选项:


Sandbox

  • 来自Chromium的沙盒特性,如果开启了这个选项, 渲染进程将运行在沙箱中,限制了大多数系统资源的访问,包括文件读写,新进程启动等, preload.js和网页中的js都会受到这个选项的影响
  • 值得注意的是,这个选项会随着Node Integration的开启而关闭
  • Sandbox选项从Electron 20开始默认为开启状态
  • 如果开启,我们就不能通过chromium v8 Nday RCE也不能通过渲染进程Nodejs共享库直接执行命令


Node Integration

  • Node集成,是否开启网页Js Nodej共享库的访问,如果开启的话,网页js将拥有直接Nodejs的执行权限,包括进程启动,文件加载等
  • preload.js Node集成是一直开启的,不受这个选项影响
  • 即使这个选项开启,上下文隔离选项开启的话,网页Js仍然无法访问Nodejs共享库


Context Isolation

  • 上下文隔离是Electron的一个特性,使用了与Chromium相同的Content Scripts技术来实现。确保preload脚本和网页js在一个独立的上下文环境中
  • 一旦开启,渲染页面的js中无法将引入Electron和Node的各种模块
  • 如果想在其中使用这部分功能,需要配置preload.js,使用contextBridge来暴露全局接口到渲染页面的脚本中
  • Electron 12开始默认启用


04 Electron利用方法

我们对选项的不同组合情况进行讨论, 这里我们为了方便讨论,规定:

  • Node Integration为NI
  • Context Isolation为CISO
  • Sandbox为SBX


NI为true, CISO为 false,无沙箱

这种情况是最简单的情况,允许了页面之间访问nodejs共享库,并且没有开启沙箱。只要我们能获取目标应用的一个XSS漏洞,就能直接通过访问NodeJS共享库,升级为XSS漏洞


在man.js中webPreferences中配置了nodeIntegration为true, contextIsolation为false,默认情况下nodeIntegration为true,沙箱就会关闭


script直接执行nodejs代码,即可获取shell


NI为false, CISO为false,SBX为false

在这种情况下,相比于第一种情况,虽然关闭了Nodejs集成,导致我们不能在web页面上下文访问Nodejs共享库。但是因为上下文隔离没有开启,web页面和preload.js处于同一上下文中,导致我们可以通过污染原型链,获取preload,js的函数,进行ipcmain调用,命令执行等


原型链污染获取__webpack_require__

通过如下代码进行原型链污染,可以获取到__webpack_require__函数,进而引入remote/IPC进行进一步利用

<script>
const origEndWith = String.prototype.endsWith;
String.prototype.endsWith = function(...args) {
if (args && args[0] === "/electron") {
String.prototype.endsWith = origEndWith;
return true;
}
return origEndWith.apply(this, args);
}

const origCallMethod = Function.prototype.call;
Function.prototype.call = function(...args){
if(args[3] && args[3].name === "__webpack_require__") {
window.__webpack_require__ = args[3];
Function.prototype.call = origCallMethod;
}
return origCallMethod.apply(this, args);
}
console.log(window.__webpack_require__);
</script>


版本限制

Electron<10

- 可以使用原型链污染获取remote/IPC模块

- Remote模块可以直接通过主进程执行node js绕过沙箱


Electron 10<version<14

- 可以使用原型链污染获取remote/IPC模块

- 需要Remote Module Explicitly Enabled,才可以使用remote模块RCE

- 主进程IPC存在错误配置,通过进程间通信IPC,进行RCE


Electron >14

- 只能通过原型链污染获取IPC模块

主进程IPC存在错误配置,通过进程间通信IPC,进行RCE


利用__webpack_require__进行RCE

无沙箱的情况下,获取openExternal直接执行系统命令

window.__webpack_require__('./lib/common/api/shell.ts').default.openExternal('file:///System/Applications/Calculator.app/Contents/MacOS/Calculator')

window.__webpack_require__("module")._load("child_process").execFile("/System/Applications/Calculator.app/Contents/MacOS/Calculator")


有沙箱的情况下,获取ipc,通过主进程的错误配置RCE

ipc = __webpack_require__('./lib/renderer/ipc-renderer-internal.ts').ipcRendererInternal
a=__webpack_require__(
'./node modules/process/browser.is')._linkedBinding('electron_renderer_ipc')


以下为无沙箱直接使用openExternal RCE的例子


NI为true/false, CISO为true,SBX为false

因为没有开启沙箱,通过Chrome渲染进程远程代码执行漏洞,就可以直接RCE。比如Chromium的CVE-2021-21220漏洞, 影响Chromium 83、86、87、88版本,如果electorn内置了Chromium就可以通过XSS,直接攻击,进行RCE。


NI:false, CISO:true, SBX为true

有沙箱, 我们只能通过IPC进行攻击,但是如果我们js处于iframe之中,可能没有ipc访问权限, 这里分享一些绕过思路。


iframe下无ipc接口绕过

默认情况下iframe是没有preload.js暴露的ipc接口的,如果我们获取了一个Iframe的上下文XSS,就不能通过IPC的错误配置RCE。


这里提供了一个绕过手法nodeIntegrationInSubFrames选项,代表是否开启iframe环境的预加载脚本执行,如果开启我们就能在Iframe上下文访问contextBridge暴露的接口。


这个选项是一个实验选项,默认是关闭状态


但是我们可以通过v8 renderer exploit Nday获得的任意内存写的能力,覆盖它为开启


从而获得在Iframe上下文访问contextBridge能力,进行RCE。


关闭CISO,直接使用IPC,绕过限制

如果在渲染进程的contextBridge存在一些限制,导致我们无法直接执行恶意脚本,比如如下渲染进程的contextBridge限制了openPath的协议只能为http等安全协议,导致无法利用


我们可以通过v8 renderer exploit关闭CISO选项,然后通过原型链污染直接获取ipc,直接使用进程间通信访问main进程的ipcMain监听的方法,绕过contextBridge的限制


关闭CISO,使用原型链污染获取remote模块进行RCE

在Electron低版本,一旦关闭了CISO, 我们也可以通过原型链污染泄露remore模块的方式,远程将js代码发送给main进程,通过main.js执行的方式进行RCE。


下图是示例的污染方式,获取require函数,引入remote.ts,引入remote模块,执行系统命令


05 总结

Electron是一个桌面应用程序的框架,具有方便的跨平台特性,大量的桌面应用都使用Electron开发,如VSCode, Discord等。如果开发者不注重Electron的安全,开启了一些高危选项,很可能导致安全问题。本文讨论了影响Electron安全的3个比较重要的选项,Sandbox,Context Isolation,Node Integration。以及这些选项的状态组合之下,对Electron可能具有的攻击方法。希望能起到抛砖引玉的作用。

from https://mp.weixin.qq.com/s/E9cBVrIikwDm1X586xl-vw