这是一个示例,演示如何快速在你的 Electron 项目中启用字节码保护,没有多余的废话。
环境
tech | version |
---|---|
electron | 30.0.6 |
webpack | 5.91.0 |
@herberttn/bytenode-webpack-plugin | 2.3.1 |
nodejs | v20.14.0 |
步骤
Webpack 配置
1// 引入依赖
2const { BytenodeWebpackPlugin } = require('@herberttn/bytenode-webpack-plugin');
3// 在生产环境启用
4const isEnvProduction = process.env.NODE_ENV === 'production';
5...
6plugins: [
7 isEnvProduction && new BytenodeWebpackPlugin({ compileForElectron: true }),
8],
9...
10// main,preload,renderer 需要更改 entry 配置。我使用了 webpack-merge,如果你没有使用,忽略即可。
11// main
12const mainConfig = merge(commonConfig, {
13 // entry: './src/main/main.ts',
14 entry: {
15 main: './src/main/main.ts',
16 },
17 target: 'electron-main',
18 output: {
19 filename: '[name].js',
20 devtoolModuleFilenameTemplate: '[absolute-resource-path]',
21 },
22 ...
23})
24// preload
25const preloadConfig = merge(commonConfig, {
26 // entry: './src/preload/preload.ts',
27 entry: {
28 preload: './src/preload/preload.ts',
29 },
30 target: 'electron-preload',
31 output: {
32 filename: '[name].js',
33 devtoolModuleFilenameTemplate: '[absolute-resource-path]',
34 },
35});
36// renderer
37const rendererConfig = merge(commonConfig, {
38 entry: {
39 renderer: './src/renderer/renderer.tsx',
40 },
41 target: 'electron-renderer',
42 output: { devtoolModuleFilenameTemplate: '[absolute-resource-path]' },
43 plugins: [
44 new HtmlWebpackPlugin({
45 template: path.resolve(__dirname, './public/index.html'),
46 }),
47 ],
48});
Electron 入口 main.ts/main.js 配置
1 mainWindow = new BrowserWindow({
2 ...
3 webPreferences: {
4 nodeIntegration: true, // 启用 jsc 支持
5 contextIsolation: false, // false 是启用 jsc 支持,但是用不了 preload 的 contextBridge
6 preload: path.join(__dirname, './preload.js'), // bytenode 编译后生成的 js,用于加载 preload.compiled.jsc
7 webSecurity: false,
8 sandbox: false,
9 },
10});
我知道上面的配置,不符合 Electron 的默认安全配置。但是 Electron 的默认安全配置开启后,你基本上什么也做不了。
如果你希望使用字节码,你必须按照以上配置。
preload contextBridge 修复
contextIsolation: false
会导致 contextBridge 无法使用,这又是 Electron 的一个有趣决定之一。
contextBridge 无法使用,那么你就无法在使用 ipc,当然,你也不需要了。
此时你可以在 renderer 中直接操作 node 的 api,如 fs 等。但是我建议还是通过 preload 中转一下,凡事留一线,日后好相见。
1- import { contextBridge } from 'electron';
2- import ipcAPI from '_preload/ipc-api';
3import loadAddon from "_preload/load_node_addon";
4import jb from "_preload/nodejieba";
5
6- contextBridge.exposeInMainWorld('ipcAPI', ipcAPI);
7- contextBridge.exposeInMainWorld('myplugin', loadAddon('myplugin'));
8- contextBridge.exposeInMainWorld('jb', jb);
9
10+ window.ipcAPI = ipcAPI;
11+ window.myplugin = loadAddon('myplugin');
12+ window.jb = jb;
完成
通过 webpack.js,main.js,preload.js 中的以上三处配置,你应该可以在你的项目中使用字节码了。
字节码仍然不是最终方案,因为字节码很容易被反编译,目前阶段它只是增加了初级破解者的一些成本。
有些人使用了在 rust 中编写本地插件,和字节码搭配混淆的方案,如果你对代码有强烈的保密需求,可以参考,并在可维护性和安全性上取舍。