0x01 简介
我是在这篇文章测试过程中发现 Electron 20.0
≠ sandbox:true
的,当时以为是官方弄错了,所以尝试跟官方沟通,等了一周多,但是官方一直没有给反馈,所以导致这篇文章比 sandbox 那篇文章发得晚了一些,
大家好,今天和大家讨论 nodeIntegrationInWorker
, 这个选项看起来和 nodeIntegration
很像,不过后面跟了 InWorker
,说明是在 Worker
中开启 Node.js
,默认值为 false
问题来了,什么是 Worker
呢?我看我像是 Worker
,但是这里说的是 Web Worker
Web Worker 是一项 HTML5 提出的技术,它允许在Web应用程序中创建后台线程,以实现JavaScript的多线程处理能力。具体来说,Web Worker 是一个独立于主线程(即浏览器的UI线程)运行的JavaScript线程,用于执行耗时的、计算密集型或其他可能阻塞用户界面的任务,确保这些任务不会影响到页面的响应性和用户体验。
Web Worker 常用于以下场景:
大数据处理:如批量数据过滤、排序、计算等复杂算法。 图像处理:如像素操作、压缩、解码等图形处理任务。 科学计算:如数学模型的迭代计算、物理模拟等高性能计算需求。 离线存储处理:如 IndexedDB 数据的批量读写、同步操作。 长时间运行的任务:如长轮询、定时任务、长时间运行的计数器等,避免影响页面响应性。 网络通信:处理 XMLHttpRequest 或 Fetch API 请求,尤其是处理大量并发请求或流式数据。 通过使用 Web Worker,开发者能够有效地解决JavaScript单线程环境下可能出现的性能瓶颈问题,确保即使在执行繁重任务时,Web应用仍能保持流畅的用户界面和良好的响应速度。
JavaScript
多线程一直是一个非常别扭的事情,用过的人都迷糊,有了 Worker
以后应该会缓解一些
https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers
https://www.electronjs.org/zh/docs/latest/api/structures/browser-window-options
https://www.electronjs.org/zh/docs/latest/tutorial/multithreading
公众号开启了留言功能,欢迎大家留言讨论~
这篇文章也提供了 PDF
版本及 Github
,见文末
-
0x01 简介
-
0x02 Web Worker
-
1. Web Worker 简介
-
2. 创建 Web Worker
-
3. 主线程与 Worker 通信
-
4. 错误处理
-
5. 关闭 Worker
-
0x03 测试 nodeIntegrationInWorker
-
1. 功能测试
-
2. 特别注意
-
3. sandbox显式地设置为 true
-
0x04 总结
-
0x05 PDF版 & Github
-
往期文章
0x02 Web Worker
1. Web Worker 简介
一个 worker
是使用一个构造函数创建的一个对象(例如 Worker()
)运行一个命名的 JavaScript
文件
这个文件包含将在 worker
线程中运行的代码; worker
运行在另一个全局上下文中,不同于当前的window
。因此,在 Worker
内通过 window
获取全局作用域(而不是self
)将返回错误
Worker
分为两类
-
专用
Worker
一对一关联,即一个
Worker
服务于一个主线程,由创建它的脚本独享 -
共享
Worker
一对多关联,一个共享
Worker
可以被多个页面(主线程)访问和通信,适用于跨页面共享资源或协同工作
从 Electron
的官方描述来看,nodeIntegrationInWorker
目前只支持专用 Worker
,而且必须将 sandbox
设置为 false
才有效
关键的是,从目前 Electron
官方描述来看,Node.js
似乎还没有做好关于 Worker
的准备
![nodeIntegrationInWorker | Electron 安全 nodeIntegrationInWorker | Electron 安全](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/05/1-1714965435.png)
https://www.electronjs.org/zh/docs/latest/tutorial/multithreading
更多关于 Web Worker
的介绍可以参考下面的文章
https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Workers_API/Using_web_workers#%E4%B8%93%E7%94%A8_worker
https://www.ruanyifeng.com/blog/2018/07/web-worker.html
2. 创建 Web Worker
如何创建一个专用 Worker
呢?
const myWorker = new Worker("worker.js");
这样就生成了一个 Web Worker
,Web Worker
会运行 worker.js
中的代码,其中 worker.js
也可以是一个URL
,但必须是同源的
3. 主线程与 Worker 通信
这有点像 Electron
中的主进程和渲染进程通信了。主线程和 Worker
线程的通信是通过 postMessage
和 onmessage
进行通信的
worker.js
// worker.js
self.addEventListener('message', function(e) {
const data = e.data;
// 处理收到的数据并进行计算或处理
const result = performComputation(data);
// 将结果发送回主线程
self.postMessage(result);
}, false);
function performComputation(inputData) {
// 在这里编写具体的计算逻辑
// ...
return computedResult;
}
上面的代码是一个简单的计算demo
,主进程发送数据后,它便进行一些运算,并通过 postMessage
返回给主线程
主线程这边
// 创建 Worker,传入 Worker 脚本文件的路径
const myWorker = new Worker('worker.js');
// 主线程向 Worker 发送消息
myWorker.postMessage(someInputData);
// 监听 Worker 返回的结果
myWorker.addEventListener('message', function(e) {
const result = e.data;
console.log('Received result from Worker:', result);
// 根据结果进行后续操作
}, false);
4. 错误处理
为确保程序健壮性,应在主线程中监听 Worker
的 error
事件以处理 Worker
执行过程中的错误
myWorker.addEventListener('error', function(errorEvent) {
console.error('Error occurred in Worker:', errorEvent.message);
}, false);
5. 关闭 Worker
当不再需要 Worker
时,调用 worker.terminate()
方法来停止 Worker
并释放其资源。
myWorker.terminate();
0x03 测试 nodeIntegrationInWorker
main.js
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron')
const path = require('path')
function createWindow () {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 1600,
height: 1200,
webPreferences: {
nodeIntegrationInWorker: true,
sandbox: false,
preload: path.join(__dirname, 'preload.js')
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// mainWindow.loadURL('https://iqinban.com/')
// Open the DevTools.
mainWindow.webContents.openDevTools()
}
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
We are using Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
and Electron <span id="electron-version"></span>.
<!-- You can also require other files to run in this process -->
<script src="./renderer.js"></script>
</body>
</html>
renderer.js
// 创建 Worker,传入 Worker 脚本文件的路径
const myWorker = new Worker('worker.js');
// 主线程向 Worker 发送消息
myWorker.postMessage("message from main -> worker");
// 监听 Worker 返回的结果
myWorker.addEventListener('message', function(e) {
const result = e.data;
console.log('Received result from Worker:', result);
// 根据结果进行后续操作
}, false);
worker.js
// worker.js
self.addEventListener('message', function(e) {
const data = e.data;
// 处理收到的数据并进行计算或处理
console.log(data)
const result = "OK!!!"
// 将结果发送回主线程
self.postMessage(result);
}, false);
1. 功能测试
![nodeIntegrationInWorker | Electron 安全 nodeIntegrationInWorker | Electron 安全](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/05/10-1714965436.png)
![nodeIntegrationInWorker | Electron 安全 nodeIntegrationInWorker | Electron 安全](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/05/8-1714965438.png)
可以看到, Worker
功能是没有问题的,现在测试一下 Node.js
的能力
添加如下 Payload
require('child_process').exec('open /System/Applications/Calculator.app')
![nodeIntegrationInWorker | Electron 安全 nodeIntegrationInWorker | Electron 安全](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/05/8-1714965440.png)
![nodeIntegrationInWorker | Electron 安全 nodeIntegrationInWorker | Electron 安全](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/05/6-1714965441.png)
成功打开计算器,Worker
确实获得了 Node.js
的能力,此时 nodeIntegration
处于默认的 false
,这两个选项之间没有关系
如果开启 sandbox
![nodeIntegrationInWorker | Electron 安全 nodeIntegrationInWorker | Electron 安全](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/05/10-1714965443.png)
Worker
不再具备 Node.js
能力
2. 特别注意
有趣的是,我们知道,sandbox
选项默认在 Electron 20.0
中开始默认为 true
,但是经过我的测试,只有当 sandbox
被显式地设置为 true
时,才会阻止 Worker
获得 Node.js
的能力,当然前提是 nodeIntegrationInWorker
被设置为 true
![nodeIntegrationInWorker | Electron 安全 nodeIntegrationInWorker | Electron 安全](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/05/7-1714965444.png)
![nodeIntegrationInWorker | Electron 安全 nodeIntegrationInWorker | Electron 安全](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/05/6-1714965446.png)
令人震惊的是,我顺带测试了一下 nodeIntegration
![nodeIntegrationInWorker | Electron 安全 nodeIntegrationInWorker | Electron 安全](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/05/2-1714965448.png)
![nodeIntegrationInWorker | Electron 安全 nodeIntegrationInWorker | Electron 安全](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/05/7-1714965449.png)
对于 nodeIntegration
来说也是一样的
3. sandbox显式地设置为 true
既然有了上面的发现,那么我们接下来的测试将 sandbox
显式地设置为 true
,看看在各个版本会不会有什么不一样
![nodeIntegrationInWorker | Electron 安全 nodeIntegrationInWorker | Electron 安全](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/05/7-1714965451.png)
![nodeIntegrationInWorker | Electron 安全 nodeIntegrationInWorker | Electron 安全](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/05/8-1714965452.png)
![nodeIntegrationInWorker | Electron 安全 nodeIntegrationInWorker | Electron 安全](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/05/5-1714965453.png)
![nodeIntegrationInWorker | Electron 安全 nodeIntegrationInWorker | Electron 安全](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/05/4-1714965454.png)
![nodeIntegrationInWorker | Electron 安全 nodeIntegrationInWorker | Electron 安全](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/05/4-1714965455.png)
![nodeIntegrationInWorker | Electron 安全 nodeIntegrationInWorker | Electron 安全](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/05/7-1714965456.png)
![nodeIntegrationInWorker | Electron 安全 nodeIntegrationInWorker | Electron 安全](https://ctfiot.oss-cn-beijing.aliyuncs.com/uploads/2024/05/5-1714965457.png)
可以看到,测试了 Electron 5.0、6.0、12.0、19.0、20.0、21.0、30.0
表现是一致的,如果显式地设置了 sandbox: true
,则即使设置nodeIntegrationInWorker
为 true
, Worker
也不具备 Node.js
的能力
0x04 总结
nodeIntegrationInWorker
配置项的作用是赋予 Web Worker
Node.js
的能力,这个能力只有在 sandbox
没有显式地设置为 true
时起作用
一定要注意,虽然官方曾说在 Electron 20.0
版本开始,默认对渲染进程沙盒化,但是实际测试发现,如果没有显式的设置 sandbox:true
,即使是 Electron 20.0
版本以后,也不会对 nodeIntegration
、nodeIntegrationInWorker
、preload
的 Node.js
执行造成阻碍
0x05 PDF版 & Github
PDF
版
https://pan.baidu.com/s/1xdKd-mTmRaQGCFSX5_7BIw?pwd=ix74
Github
https://github.com/Just-Hack-For-Fun/Electron-Security
往期文章
原文始发于微信公众号(NOP Team):nodeIntegrationInWorker | Electron 安全