electron 中的那些事(很关键)-核心要点补充

文章目录

    • [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'
});

三、额外安全加固措施

  1. 禁用渲染进程的 evalremote:避免代码注入导致敏感信息泄露;

  2. 加密存储敏感数据:即使 Token 存储在文件/密钥库,也要通过 AES 等算法加密;

  3. 限制 IPC 通信的权限:验证 IPC 请求的发送者(如窗口 ID、WebContents ID),拒绝非法请求;

  4. 及时清理 Token:应用退出/用户登出时,立即清空主进程内存中的 Token,并删除存储的 Token;

  5. 启用 Content-Security-Policy (CSP) :在 index.html 中设置 CSP,限制脚本执行来源:

    html 复制代码
    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self';">

总结

  1. 环境变量安全 :仅通过预加载脚本的 contextBridge 暴露非敏感环境变量,禁用渲染进程的 Node.js 集成和上下文隔离;
  2. 敏感 Token 传递:优先使用"主进程代理 API"方案,避免渲染进程直接接触 Token;若必须传递,使用系统密钥库存储并通过鉴权后的 IPC 临时获取;
  3. 核心安全原则:敏感数据仅保留在主进程,渲染进程仅通过受控的 IPC 接口交互,禁止直接暴露任何敏感信息。

在非 HTTPS(纯 HTTP)环境下,如何安全处理 Electron 中的 session 和敏感 Token 传递

你现在关注的是在非 HTTPS(纯 HTTP)环境下,如何安全处理 Electron 中的 session 和敏感 Token 传递问题,这确实是实际开发中很常见的场景,HTTP 环境下的安全风险会更高,需要针对性调整方案。

一、HTTP 环境下的核心安全风险

首先明确:HTTP 是明文传输协议,任何网络层面的拦截都能获取到传输的数据,所以我们的安全策略核心是:

  1. 尽量让敏感 Token 不出现在网络传输中(主进程代理请求);
  2. 即使必须传输,也要在应用层做加密,同时禁用 HTTP 环境下的不安全配置;
  3. 绝对不能依赖 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);
  }
}

你之前提到的 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 环境下的额外安全建议

  1. 仅限内网/测试环境使用:HTTP 明文传输的风险无法完全消除,生产环境必须升级到 HTTPS(可配置免费的 Let's Encrypt 证书);
  2. 缩短 Token 有效期:即使 Token 被抓包,也能限制攻击窗口,同时增加刷新 Token 的逻辑;
  3. 验证请求来源 :在 IPC 通信时,验证请求的发送者是合法的渲染进程(如通过 event.sender.webContents.id 校验);
  4. 内存中销毁 Token :用户登出/应用关闭时,立即将主进程中的 authToken 置空,避免内存残留。

总结

  1. 核心方案:HTTP 环境下优先使用「主进程代理 API 请求」,Token 仅保留在主进程内存,不随 HTTP 请求直接暴露;
  2. 禁用危险配置 :绝对不要在 HTTP 下使用 session 设置 Token Cookie(HttpOnly/Secure 失效);
  3. 加固措施:仅限内网使用 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 版本」:

方式 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 版本

如果你使用了需要编译的原生模块(如 serialportkeytar),必须保证:

  • 编译时使用的 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)。

三、版本选择建议

  1. 新手/稳定需求:选择最新的 Electron LTS 版本(如 28.x、30.x),对应的 Node.js 也是 LTS 版本,兼容性最好;
  2. 需使用新 Node 特性:查看官方对照表,选择内置目标 Node 版本的 Electron 版本(注意避免非 LTS 版本);
  3. 需兼容旧依赖:如果项目依赖的原生模块仅支持旧 Node 版本,需降级 Electron 到对应版本。

总结

  1. 强绑定关系:每个 Electron 版本内置固定的 Node.js 版本,无法手动修改,二者一一对应;
  2. 查询方式 :优先通过官方对照表、electron -e 命令或 process.versions 获取版本对应关系;
  3. 开发关键:原生模块需按 Electron 内置 Node 版本编译,升级 Electron 时要注意 Node/Chromium 兼容性。
相关推荐
战族狼魂2 小时前
Python 完整实现 BCrypt GUI 工具
java·前端·python
2301_789169542 小时前
ai讲React 18 + Context API 极简教程 解决深层组件调用父组件里其他组件方法
javascript·react.js·ecmascript
念念不忘 必有回响2 小时前
vue项目从零开始配置国际化
前端·javascript·vue.js
J_liaty2 小时前
前后端跨域处理全指南:Java后端+Vue前端完整解决方案
java·前端·vue.js·spring boot·后端
小二·2 小时前
Python Web 开发进阶实战:国际化(i18n)与多语言支持 —— Vue I18n + Flask-Babel 全栈解决方案
前端·vue.js·python
全栈前端老曹2 小时前
【包管理】npm最常见的10大问题故障和解决方案
前端·javascript·rust·npm·node.js·json·最佳实践
摘星编程2 小时前
React Native for OpenHarmony 实战:Easing 动画缓动函数详解
javascript·react native·react.js
weixin_427771612 小时前
pnpm 改造
前端
岁岁种桃花儿2 小时前
Spring Boot Maven插件核心配置详解:从打包到部署全流程
前端·firefox·springboot