文章目录
-
- [electron 开发中核心要点补充](#electron 开发中核心要点补充)
- 环境变量之鉴权
-
- [一、Electron 环境变量的安全配置原则](#一、Electron 环境变量的安全配置原则)
-
- [1. 基础安全配置(禁用渲染进程的危险能力)](#1. 基础安全配置(禁用渲染进程的危险能力))
- [2. 非敏感环境变量的安全传递](#2. 非敏感环境变量的安全传递)
- [二、敏感信息(如 Token)的安全传递方案](#二、敏感信息(如 Token)的安全传递方案)
-
- [方案 1:主进程代理所有 API 请求(最优)](#方案 1:主进程代理所有 API 请求(最优))
- [方案 2:Token 存储在安全位置,按需通过 IPC 临时获取(次优)](#方案 2:Token 存储在安全位置,按需通过 IPC 临时获取(次优))
- [方案 3:使用 session 隔离(兜底)](#方案 3:使用 session 隔离(兜底))
- 三、额外安全加固措施
- 总结
- [在非 HTTPS(纯 HTTP)环境下,如何安全处理 Electron 中的 session 和敏感 Token 传递](#在非 HTTPS(纯 HTTP)环境下,如何安全处理 Electron 中的 session 和敏感 Token 传递)
-
- [一、HTTP 环境下的核心安全风险](#一、HTTP 环境下的核心安全风险)
- [二、HTTP 环境下 Session/Token 的安全处理方案](#二、HTTP 环境下 Session/Token 的安全处理方案)
-
- [1. 核心方案:主进程代理 API 请求(适配 HTTP)](#1. 核心方案:主进程代理 API 请求(适配 HTTP))
- [2. 禁用 HTTP 环境下的 Session Cookie 方案(关键!)](#2. 禁用 HTTP 环境下的 Session Cookie 方案(关键!))
- [3. 兜底方案:HTTP 请求加密(应用层加固)](#3. 兜底方案:HTTP 请求加密(应用层加固))
- [4. Electron Session 的安全配置(HTTP 环境)](#4. Electron Session 的安全配置(HTTP 环境))
- [三、HTTP 环境下的额外安全建议](#三、HTTP 环境下的额外安全建议)
- 总结
- [electron 版本 与 node 版本之间的关系](#electron 版本 与 node 版本之间的关系)
-
- [一、核心关系:Electron 内置 Node.js](#一、核心关系:Electron 内置 Node.js)
-
- [1. 版本绑定的原因](#1. 版本绑定的原因)
- [2. 如何查询对应关系](#2. 如何查询对应关系)
-
- [方式 1:官方版本对照表(推荐)](#方式 1:官方版本对照表(推荐))
- [方式 2:命令行查看当前 Electron 的 Node 版本](#方式 2:命令行查看当前 Electron 的 Node 版本)
- [方式 3:运行时获取版本信息](#方式 3:运行时获取版本信息)
- 二、开发中的关键注意事项
-
- [1. 原生模块编译依赖 Node 版本](#1. 原生模块编译依赖 Node 版本)
- [2. 版本升级的兼容性风险](#2. 版本升级的兼容性风险)
- [3. 长期支持(LTS)版本选择](#3. 长期支持(LTS)版本选择)
- 三、版本选择建议
- 总结
electron 开发中核心要点补充
electron 向渲染进程提供哪些环境变量才能保证应用安全,敏感的如token 怎么传递才能满足渲染进程框架鉴权的需求
session存储的安全性在https可以设置,如果不是https 是http 怎么办,session 如何处理
electron 版本 与 node 版本之间的关系
环境变量之鉴权
一、Electron 环境变量的安全配置原则
首先要明确:绝对不要直接将敏感环境变量暴露给渲染进程 。Electron 中渲染进程默认可以通过 process.env 访问 Node.js 环境变量,这会带来极大安全风险。
1. 基础安全配置(禁用渲染进程的危险能力)
先通过主进程配置限制渲染进程的权限,从根源降低风险:
javascript
// main.js (主进程)
const { app, BrowserWindow } = require('electron');
const path = require('path');
function createWindow() {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// 核心安全配置
nodeIntegration: false, // 禁用渲染进程的 Node.js 集成(关键!)
contextIsolation: true, // 开启上下文隔离(关键!)
sandbox: true, // 可选:开启沙箱,进一步限制权限
preload: path.join(__dirname, 'preload.js'), // 预加载脚本(唯一安全通道)
// 禁用远程模块(Electron 14+ 已移除,低版本需手动禁用)
enableRemoteModule: false,
// 限制脚本执行(可选,根据业务需求)
allowRunningInsecureContent: false,
webSecurity: true // 启用网页安全策略
}
});
mainWindow.loadFile('index.html');
}
app.whenReady().then(createWindow);
2. 非敏感环境变量的安全传递
非敏感的环境变量(如应用版本、API 基础地址)可通过预加载脚本的 contextBridge 暴露,而非直接暴露 process.env:
javascript
// preload.js (预加载脚本,必须是独立文件)
const { contextBridge } = require('electron');
// 仅暴露非敏感环境变量
const safeEnv = {
API_BASE_URL: process.env.API_BASE_URL || 'https://api.example.com',
APP_VERSION: process.env.APP_VERSION || '1.0.0'
};
// 向渲染进程暴露安全的环境变量(命名空间需唯一,避免冲突)
contextBridge.exposeInMainWorld('electronSafeEnv', safeEnv);
渲染进程中使用:
javascript
// renderer.js (渲染进程)
console.log(window.electronSafeEnv.API_BASE_URL); // 仅能访问暴露的非敏感变量
二、敏感信息(如 Token)的安全传递方案
Token 属于核心敏感数据,绝对不能通过环境变量、全局变量或预加载脚本直接暴露,推荐以下 3 种安全方案(优先级从高到低):
方案 1:主进程代理所有 API 请求(最优)
核心思路:渲染进程仅传递"请求参数",不接触 Token;主进程持有 Token 并代理所有 API 调用,渲染进程仅接收最终结果。
javascript
// 1. 主进程 (main.js) - 持有 Token 并监听 IPC 请求
const { ipcMain } = require('electron');
let authToken = ''; // 仅在主进程存储 Token
// 初始化 Token(如从安全存储读取)
function initToken() {
authToken = 'your-secure-token-from-storage'; // 从加密文件/系统密钥库读取
}
// 监听渲染进程的 API 请求
ipcMain.handle('api:request', async (event, options) => {
try {
// 主进程携带 Token 发起请求
const response = await fetch(options.url, {
method: options.method || 'GET',
headers: {
'Authorization': `Bearer ${authToken}`, // Token 仅在主进程使用
'Content-Type': 'application/json',
...options.headers
},
body: options.body ? JSON.stringify(options.body) : null
});
const data = await response.json();
return { success: true, data };
} catch (error) {
return { success: false, error: error.message };
}
});
// 2. 预加载脚本 (preload.js) - 暴露安全的 API 调用方法
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
// 暴露 API 请求方法,渲染进程仅传递参数,不接触 Token
requestAPI: (options) => ipcRenderer.invoke('api:request', options)
});
// 3. 渲染进程 (renderer.js) - 调用 API,无感知 Token
async function fetchUserInfo() {
const result = await window.electronAPI.requestAPI({
url: '/api/user/info',
method: 'GET'
});
if (result.success) {
console.log('用户信息:', result.data);
} else {
console.error('请求失败:', result.error);
}
}
方案 2:Token 存储在安全位置,按需通过 IPC 临时获取(次优)
若必须让渲染进程短暂持有 Token(如适配现有前端鉴权框架),可将 Token 存储在主进程的安全存储(如 keytar 或 Electron 的安全存储 API),渲染进程通过鉴权后临时获取:
javascript
// 1. 主进程 - 安全存储/获取 Token
const keytar = require('keytar'); // 需安装:npm install keytar
const SERVICE_NAME = 'YourAppName';
const ACCOUNT_NAME = 'user-auth';
// 存储 Token 到系统密钥库(macOS Keychain/Windows Credential Manager)
ipcMain.handle('token:save', async (_, token) => {
await keytar.setPassword(SERVICE_NAME, ACCOUNT_NAME, token);
return true;
});
// 鉴权通过后临时获取 Token(需验证请求合法性)
ipcMain.handle('token:get', async (event) => {
// 可选:验证请求来源(如窗口 ID、用户操作状态)
const window = BrowserWindow.fromWebContents(event.sender);
if (window && window.isFocused()) { // 简单的合法性校验
return await keytar.getPassword(SERVICE_NAME, ACCOUNT_NAME);
}
throw new Error('非法的 Token 请求');
});
// 2. 预加载脚本 - 暴露安全的 Token 操作方法
contextBridge.exposeInMainWorld('electronAPI', {
saveToken: (token) => ipcRenderer.invoke('token:save', token),
getToken: () => ipcRenderer.invoke('token:get')
});
// 3. 渲染进程 - 仅在鉴权时临时获取 Token
async function initAuth() {
const token = await window.electronAPI.getToken();
// 仅在当前会话使用,用完立即清空(如存储在内存,不写入 localStorage)
const authInstance = new AuthFramework(token); // 适配前端鉴权框架
}
方案 3:使用 session 隔离(兜底)
若以上方案无法适配,可将 Token 存储在 Electron 的 session 中(渲染进程无法直接读取,仅请求时自动携带):
javascript
// 主进程
const { session } = require('electron');
// 设置 Cookie(HttpOnly + Secure,渲染进程无法通过 JS 读取)
session.defaultSession.cookies.set({
url: 'https://api.example.com',
name: 'auth_token',
value: 'your-secure-token',
httpOnly: true, // 关键:禁止 JS 读取
secure: true, // 仅 HTTPS 请求携带
sameSite: 'strict'
});
三、额外安全加固措施
-
禁用渲染进程的
eval和remote:避免代码注入导致敏感信息泄露; -
加密存储敏感数据:即使 Token 存储在文件/密钥库,也要通过 AES 等算法加密;
-
限制 IPC 通信的权限:验证 IPC 请求的发送者(如窗口 ID、WebContents ID),拒绝非法请求;
-
及时清理 Token:应用退出/用户登出时,立即清空主进程内存中的 Token,并删除存储的 Token;
-
启用 Content-Security-Policy (CSP) :在
index.html中设置 CSP,限制脚本执行来源:html<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self';">
总结
- 环境变量安全 :仅通过预加载脚本的
contextBridge暴露非敏感环境变量,禁用渲染进程的 Node.js 集成和上下文隔离; - 敏感 Token 传递:优先使用"主进程代理 API"方案,避免渲染进程直接接触 Token;若必须传递,使用系统密钥库存储并通过鉴权后的 IPC 临时获取;
- 核心安全原则:敏感数据仅保留在主进程,渲染进程仅通过受控的 IPC 接口交互,禁止直接暴露任何敏感信息。
在非 HTTPS(纯 HTTP)环境下,如何安全处理 Electron 中的 session 和敏感 Token 传递
你现在关注的是在非 HTTPS(纯 HTTP)环境下,如何安全处理 Electron 中的 session 和敏感 Token 传递问题,这确实是实际开发中很常见的场景,HTTP 环境下的安全风险会更高,需要针对性调整方案。
一、HTTP 环境下的核心安全风险
首先明确:HTTP 是明文传输协议,任何网络层面的拦截都能获取到传输的数据,所以我们的安全策略核心是:
- 尽量让敏感 Token 不出现在网络传输中(主进程代理请求);
- 即使必须传输,也要在应用层做加密,同时禁用 HTTP 环境下的不安全配置;
- 绝对不能依赖 HTTP 的 Cookie(如 HttpOnly)做安全防护。
二、HTTP 环境下 Session/Token 的安全处理方案
1. 核心方案:主进程代理 API 请求(适配 HTTP)
这依然是最优方案,且在 HTTP 环境下更重要------Token 仅在主进程内存中,不随 HTTP 请求直接暴露(即使 HTTP 被抓包,也抓不到 Token,因为 Token 由主进程添加后再发请求)。
修改适配 HTTP 的完整代码:
javascript
// 1. 主进程 (main.js) - 代理 HTTP 请求,Token 仅在主进程
const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path');
let authToken = ''; // Token 仅存主进程内存,不暴露给渲染进程
// 初始化 Token(从安全存储读取,而非网络/渲染进程)
function initToken() {
// 示例:从加密文件读取,而非 HTTP 响应直接获取
authToken = 'your-encrypted-token-from-local-storage';
}
// 监听渲染进程的 API 请求(适配 HTTP)
ipcMain.handle('api:request', async (event, options) => {
try {
// 主进程拼接 Token 后发起 HTTP 请求
const response = await fetch(options.url, {
method: options.method || 'GET',
headers: {
'Authorization': `Bearer ${authToken}`, // Token 仅主进程使用
'Content-Type': 'application/json',
...options.headers
},
body: options.body ? JSON.stringify(options.body) : null,
// 禁用 HTTP 重定向(减少劫持风险)
redirect: 'manual'
});
const data = await response.json();
return { success: true, data };
} catch (error) {
return { success: false, error: error.message };
}
});
function createWindow() {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js'),
enableRemoteModule: false,
webSecurity: false, // 仅 HTTP 环境下临时关闭(HTTPS 必须开启)
allowRunningInsecureContent: true // 允许 HTTP 内容(仅测试/内网环境)
}
});
mainWindow.loadFile('index.html');
initToken();
}
app.whenReady().then(createWindow);
// 2. 预加载脚本 (preload.js) - 无变化,仅暴露受控接口
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electronAPI', {
requestAPI: (options) => ipcRenderer.invoke('api:request', options)
});
// 3. 渲染进程 (renderer.js) - 调用 HTTP API,无感知 Token
async function fetchData() {
// 目标地址是 HTTP,渲染进程仅传 URL,不接触 Token
const result = await window.electronAPI.requestAPI({
url: 'http://your-api-server.com/user/info',
method: 'GET'
});
if (result.success) {
console.log('数据:', result.data);
}
}
2. 禁用 HTTP 环境下的 Session Cookie 方案(关键!)
你之前提到的 session 设置 Cookie 方案,在 HTTP 环境下完全不可用 ------因为 secure: true 要求 HTTPS,而去掉 secure: true 后,Cookie 会以明文传输,且渲染进程可读取,风险极高。
❌ 绝对不要在 HTTP 环境下用以下代码:
javascript
// 危险!HTTP 环境下禁用此写法
session.defaultSession.cookies.set({
url: 'http://api.example.com',
name: 'auth_token',
value: 'your-token',
httpOnly: true, // HTTP 下 HttpOnly 无法防网络抓包
secure: false, // 去掉 secure 后 Cookie 明文传输
sameSite: 'strict'
});
3. 兜底方案:HTTP 请求加密(应用层加固)
如果你的 HTTP 接口无法修改,且必须让请求携带 Token,可在主进程对请求体/Header 做轻量加密,服务端解密:
javascript
// 主进程 - 加密 Token 后再放入 HTTP 请求头
const crypto = require('crypto');
// 加密函数(示例:AES 加密,密钥仅主进程和服务端知晓)
function encryptToken(token) {
const key = crypto.scryptSync('your-server-shared-secret', 'salt', 32);
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
let encrypted = cipher.update(token, 'utf8', 'hex');
encrypted += cipher.final('hex');
return { encrypted, iv: iv.toString('hex') };
}
// 代理请求时加密 Token
ipcMain.handle('api:request', async (event, options) => {
const { encrypted, iv } = encryptToken(authToken);
const response = await fetch(options.url, {
method: options.method || 'GET',
headers: {
'X-Encrypted-Token': encrypted, // 加密后的 Token
'X-Encrypted-IV': iv, // 初始化向量
...options.headers
}
});
// ... 后续逻辑不变
});
4. Electron Session 的安全配置(HTTP 环境)
即使使用 HTTP,也要对 Electron 的 session 做安全限制,避免额外风险:
javascript
// 主进程 - Session 安全配置
const { session } = require('electron');
app.whenReady().then(() => {
// 禁用第三方 Cookie(减少追踪/劫持风险)
session.defaultSession.setCookie({
name: 'disable-third-party-cookies',
value: '1',
url: 'http://your-api-server.com'
});
// 拦截不安全的跳转/请求
session.defaultSession.webRequest.onBeforeRequest((details, callback) => {
// 仅允许访问指定的 HTTP 域名,拒绝其他请求
const allowedDomains = ['http://your-api-server.com'];
if (!allowedDomains.some(domain => details.url.startsWith(domain))) {
callback({ cancel: true }); // 拒绝非法域名请求
} else {
callback({ cancel: false });
}
});
});
三、HTTP 环境下的额外安全建议
- 仅限内网/测试环境使用:HTTP 明文传输的风险无法完全消除,生产环境必须升级到 HTTPS(可配置免费的 Let's Encrypt 证书);
- 缩短 Token 有效期:即使 Token 被抓包,也能限制攻击窗口,同时增加刷新 Token 的逻辑;
- 验证请求来源 :在 IPC 通信时,验证请求的发送者是合法的渲染进程(如通过
event.sender.webContents.id校验); - 内存中销毁 Token :用户登出/应用关闭时,立即将主进程中的
authToken置空,避免内存残留。
总结
- 核心方案:HTTP 环境下优先使用「主进程代理 API 请求」,Token 仅保留在主进程内存,不随 HTTP 请求直接暴露;
- 禁用危险配置 :绝对不要在 HTTP 下使用
session设置 Token Cookie(HttpOnly/Secure 失效); - 加固措施:仅限内网使用 HTTP,对请求中的敏感信息做应用层加密,同时限制渲染进程的请求范围。
electron 版本 与 node 版本之间的关系
你想了解 Electron 版本和 Node.js 版本之间的对应关系,这是开发 Electron 应用时的一个关键知识点,直接影响到依赖安装、API 兼容性和应用打包。
一、核心关系:Electron 内置 Node.js
Electron 本质上是"Chromium + Node.js + 原生 API"的组合包,每个 Electron 版本都会内置一个特定版本的 Node.js,二者是强绑定关系------你无法自由选择 Electron 应用运行时的 Node.js 版本,只能使用 Electron 内置的那个版本。
1. 版本绑定的原因
- Electron 的底层功能(如原生模块、IPC 通信)依赖 Node.js 的 C++ API,不同 Node.js 版本的 API 会有变化,因此 Electron 必须固定 Node.js 版本以保证稳定性;
- Chromium 的 V8 引擎版本也与 Node.js 版本强关联(Node.js 基于 V8),Electron 需同步三者的 V8 版本。
2. 如何查询对应关系
最权威的方式有 3 种,按优先级排序:
方式 1:官方版本对照表(推荐)
Electron 官方维护了详细的版本对应表,包含「Electron 版本 ↔ Node.js 版本 ↔ Chromium 版本」:
-
官方文档地址:https://www.electronjs.org/zh/docs/latest/tutorial/electron-timelines
-
示例(部分关键版本):
Electron 版本 Node.js 版本 Chromium 版本 20.x 16.15.0 104 22.x 16.17.1 108 24.x 18.14.0 112 26.x 18.16.1 116 28.x 20.9.0 120 30.x 22.3.0 124
方式 2:命令行查看当前 Electron 的 Node 版本
如果你已安装某个版本的 Electron,可通过以下命令快速查看内置 Node 版本:
bash
# 全局安装 electron 后
electron -v # 查看 Electron 版本
electron -e "console.log(process.versions.node)" # 查看内置 Node 版本
方式 3:运行时获取版本信息
在 Electron 应用中,可通过 process.versions 对象直接获取所有组件版本:
javascript
// 主进程/预加载脚本中执行(渲染进程需通过 contextBridge 暴露)
console.log('Electron 版本:', process.versions.electron);
console.log('Node.js 版本:', process.versions.node);
console.log('Chromium 版本:', process.versions.chrome);
console.log('V8 引擎版本:', process.versions.v8);
二、开发中的关键注意事项
1. 原生模块编译依赖 Node 版本
如果你使用了需要编译的原生模块(如 serialport、keytar),必须保证:
-
编译时使用的 Node 版本 ≡ Electron 内置的 Node 版本;
-
推荐使用
electron-rebuild工具自动适配:bash# 安装依赖后执行 npx electron-rebuild
2. 版本升级的兼容性风险
升级 Electron 版本时,会同步升级内置的 Node.js 和 Chromium,可能导致:
- Node.js API 变更(如废弃某些方法、新增特性);
- Chromium 对前端 API 的支持变化(如 ES 特性、Web API);
- 原生模块需要重新编译。
3. 长期支持(LTS)版本选择
- Electron 提供 LTS 版本(支持 18 个月),优先选择 LTS 版本以保证稳定性;
- LTS 版本的 Node.js 通常也是 LTS 版本(如 Electron 28.x 内置 Node 20.x LTS)。
三、版本选择建议
- 新手/稳定需求:选择最新的 Electron LTS 版本(如 28.x、30.x),对应的 Node.js 也是 LTS 版本,兼容性最好;
- 需使用新 Node 特性:查看官方对照表,选择内置目标 Node 版本的 Electron 版本(注意避免非 LTS 版本);
- 需兼容旧依赖:如果项目依赖的原生模块仅支持旧 Node 版本,需降级 Electron 到对应版本。
总结
- 强绑定关系:每个 Electron 版本内置固定的 Node.js 版本,无法手动修改,二者一一对应;
- 查询方式 :优先通过官方对照表、
electron -e命令或process.versions获取版本对应关系; - 开发关键:原生模块需按 Electron 内置 Node 版本编译,升级 Electron 时要注意 Node/Chromium 兼容性。