doyensec/ElectronSafeUpdater

GitHub: doyensec/ElectronSafeUpdater

一个专为 Electron 应用设计的加固版安全更新框架,通过 Ed25519 签名和 SHA-512 完整性校验防止更新过程被篡改或劫持。

Stars: 5 | Forks: 0

# SafeUpdater SafeUpdater 是一个专为 Electron 应用设计的安全更新框架,优先考虑完整性、真实性和简洁性。与传统的 Electron 更新机制不同,SafeUpdater 实现了 Ed25519 签名验证、SHA-512 完整性检查和安全的文件处理,以防止篡改和受损的分发渠道,并通过加密验证限制中间人干扰的影响。 ## 核心特性 - **强加密安全性**:Ed25519 签名验证和 SHA-512 完整性检查 - **简单集成**:只需 2 行代码即可添加安全更新 - **安全降级支持**:在需要时可验证地回滚到以前的版本 - **自动更新轮询**:具有智能重试机制的可配置轮询 - **版本选择 UI**:可选的用户界面版本选择器,用于更新和降级 该软件目前仅支持 macOS。 ## 目录 - [SafeUpdater](#safeupdater) - [核心特性](#key-features) - [目录](#table-of-contents) - [快速开始](#quick-start) - [前置条件](#prerequisites) - [安装与设置](#installation--setup) - [1. 安装 SafeUpdater 包](#1-install-safeupdater-package) - [2. 配置您的 Electron 应用](#2-configure-your-electron-app) - [3. 集成到主进程](#3-integrate-into-main-process) - [4. 构建配置](#4-build-configuration) - [代码签名](#code-signing) - [功能](#features) - [安全特性](#security-features) - [更新能力](#update-capabilities) - [降级支持](#downgrade-support) - [平台支持](#platform-support) - [API 参考](#api-reference) - [入口点](#entry-point) - [`start(options)`](#startoptions) - [配置](#configuration) - [配置文件](#configuration-files) - [配置选项](#configuration-options) - [`updatesPublicKey` (string, 必填)](#updatespublickey-string-required) - [`updatesUrl` (string, 必填)](#updatesurl-string-required) - [`updatesEnabled` (boolean, 必填)](#updatesenabled-boolean-required) - [`certificateAuthority` (string, 可选)](#certificateauthority-string-optional) - [`allowInsecureTLS` (boolean, 可选, 默认值: false)](#allowinsecuretls-boolean-optional-default-false) - [`downgradeEnabled` (boolean, 可选, 默认值: false)](#downgradeenabled-boolean-optional-default-false) - [配置示例](#example-configurations) - [生产环境](#production) - [企业环境 (无自动更新)](#enterprise-no-auto-updates) - [降级支持](#downgrade-support-1) - [降级如何工作](#how-downgrades-work) - [启用降级](#enabling-downgrades) - [致谢与依赖](#credits--dependencies) ## 快速开始 ### 前置条件 - Electron 应用 - Node.js 16+ - 对 Electron 的主进程/渲染进程模型有基本了解 ## 安装与设置 **示例代码可在 [`/tools/example.main.js`](./tools/example.main.js) 中找到。** ### 1. 安装 SafeUpdater 包 ``` npm install file:../ElectronSafeUpdater ``` ### 2. 配置您的 Electron 应用 **创建 config 目录结构:** ``` your-app/ ├── config/ │ ├── default.json │ └── production.json ├── src/ │ └── index.js └── package.json ``` **config/default.json** (开发环境): ``` { "updatesPublicKey": "YOUR_PUBLIC_KEY_HEX", "allowInsecureTLS": true, "updatesEnabled": true, "updatesUrl": "https://localhost", "downgradeEnabled": true } ``` **config/production.json** (生产环境): ``` { "updatesPublicKey": "YOUR_PUBLIC_KEY_HEX", "allowInsecureTLS": false, "certificateAuthority": "-----BEGIN CERTIFICATE-----\nYOUR_CA_CERT\n-----END CERTIFICATE-----", "updatesEnabled": true, "updatesUrl": "https://updates.yourcompany.com", "downgradeEnabled": false } ``` ### 3. 集成到主进程 **src/index.js**: 静态导入: ``` import { app, BrowserWindow } from 'electron'; import * as updater from 'safeupdater'; let mainWindow; function createWindow() { mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: false, contextIsolation: true, }, }); mainWindow.loadFile('index.html'); } function getMainWindow() { return mainWindow; } // Create logger const consoleLogger = createBufferedConsoleLogger(); function createBufferedConsoleLogger() { const buffer = []; return { fatal(...args) { buffer.push({ level: 'fatal', args }); console.error(...args); }, error(...args) { buffer.push({ level: 'error', args }); console.error(...args); }, warn(...args) { buffer.push({ level: 'warn', args }); console.warn(...args); }, info(...args) { buffer.push({ level: 'info', args }); console.info(...args); }, debug(...args) { buffer.push({ level: 'debug', args }); console.debug(...args); }, trace(...args) { buffer.push({ level: 'trace', args }); console.log(...args); }, writeBufferInto(output) { for (const { level, args } of buffer) { output[level](...args); } }, }; } app.whenReady().then(async () => { createWindow(); // Initialize SafeUpdater await updater.start({ canRunSilently: true, getMainWindow: () => mainWindow, logger: consoleLogger, }); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); ``` **动态导入** (如果您的项目使用条件或动态加载): ``` const { app, BrowserWindow } = await import('electron'); const updater = await import('safeupdater'); // ... createWindow, getMainWindow, logger ... app.whenReady().then(async () => { createWindow(); await updater.start({ canRunSilently: true, getMainWindow, logger: consoleLogger, }); }); ``` ### 4. 构建配置 使用 [Electron Builder](https://github.com/electron-userland/electron-builder) 轻松构建您的应用。需要包含的关键设置: - **App 信息**:名称、版本、描述、作者。 - **文件**:包含哪些源文件和资源。 - **平台**:macOS (`dmg`, `zip`)、Windows (`nsis`)、Linux (`AppImage`, `deb`)。 - **代码签名**:macOS/Windows 的证书。 - **更新服务器**:GitHub releases、S3 或自定义服务器。 `package.json` 配置示例: ``` { "name": "my-electron-app", "version": "1.0.0", "build": { "appId": "com.example.myapp", "files": ["dist/**/*", "node_modules/**/*"], "mac": { "target": ["dmg", "zip"] }, "win": { "target": ["nsis"] }, "publish": [ { "provider": "github", "owner": "username", "repo": "your-repo" } ] } } ``` 将 `electron-builder` 命令添加到您的 **package.json** 脚本中: ``` "scripts": { "dist": "electron-builder" } ``` 运行以下命令构建应用: ``` npm run dist ``` #### 代码签名 使用 `electron-builder` 构建应用程序后,对更新程序将下载或信任的每个工件进行签名。`sign.js` 脚本可以在 `/tools` 文件夹中找到。 ``` node tools/sign.js releases/versions.json "version" ``` 签名 zip 文件: ``` node tools/sign.js releases/2.0.0/my-app-2.0.0-mac.zip "2.0.0" ``` **输出:** - 在每个工件旁边创建 `.sig` 文件 - 示例:`my-app-2.0.0-mac.zip.sig` **签名格式:** ``` Hex-encoded Ed25519 signature (128 hex characters = 64 bytes) Example: 63f5220857a58a4ebcadcd1c2cf3c1743db1381c0e1881ab84a37d5148e82eda... ``` ## 功能 ### 安全特性 - **Ed25519 数字签名**:所有版本均使用椭圆曲线加密技术进行加密签名 - **SHA-512 完整性验证**:安装前的文件哈希验证 - **证书固定**:可选的 TLS 证书颁发机构固定 - **路径验证**:防止目录遍历和基于路径的攻击 - **安全的临时文件**:使用 0o700 权限(仅限所有者)创建目录 - **签名链**:ZIP、DMG、YAML 元数据和版本清单的独立签名 - **原子操作**:失败时回滚,配合优雅的文件操作 ### 更新能力 - **自动轮询**:每 30 分钟检查一次更新,带有随机抖动 - **手动强制更新**:通过 IPC 以编程方式触发更新 - **静默与交互模式**:在无需用户确认或需确认的情况下更新 - **智能缓存**:避免重新下载相同的版本 - **自动重试**:瞬态网络错误自动重试(最长 1 天延迟) - **发布延迟推出**:基于哈希的延迟渐进发布(最长 6 小时) - **版本比较**:支持多种比较模式的语义版本检查 ### 降级支持 - **安全回滚**:加密验证降级到以前的版本 - **版本选择 UI**:用户面对的对话框,可从可用版本中进行选择 - **降级验证**:与升级相同的安全保证 - **可配置**:通过配置启用/禁用 ### 平台支持 - **当前**:macOS (DMG, ZIP) ## API 参考 ### 入口点 #### `start(options)` 初始化 SafeUpdater 系统。 **参数:** ``` interface StartOptions { canRunSilently: boolean; // If true, updates install without user prompt getMainWindow: () => BrowserWindow; // Function returning main window logger: Logger; // Logger implementation } interface Logger { fatal(...args: any[]): void; error(...args: any[]): void; warn(...args: any[]): void; info(...args: any[]): void; debug(...args: any[]): void; trace(...args: any[]): void; writeBufferInto(output: Logger): void; // Optional: replay buffered logs } ``` **示例:** ``` await updater.start({ canRunSilently: true, getMainWindow: () => mainWindow, logger: consoleLogger, }); ``` **行为:** - 检查更新是否被禁用(通过配置或平台) - 处理“下次启动时安装”场景 - 创建特定平台的更新器 - 如果启用了 `downgradeEnabled`,则触发版本选择 UI - 开始更新轮询 **抛出:** - `Error` 如果被多次调用 - `Error` 如果未提供 logger - `Error` 如果平台不是 macOS ## 配置 ### 配置文件 SafeUpdater 使用 `config` npm 包进行基于环境的配置。 **文件优先级:** 1. `config/default.json` - 基础配置 ### 配置选项 #### `updatesPublicKey` (string, 必填) 十六进制格式的 Ed25519 公钥(64 个十六进制字符)。 ``` { "updatesPublicKey": "194c304f05b2d26be44f19312f25f11f7d59809d5ba258f4d19c537c7dc3b7dd" } ``` **生成:** 生成用于签署所有版本的长期 Ed25519 密钥对。此 `generate.js` 文件可在 `/tools` 文件夹中找到。 ``` node tools/generate.js # Outputs public.key cat public.key ``` **输出:** - `private.key` - Ed25519 私钥(十六进制编码,64 个字符) - `public.key` - Ed25519 公钥(十六进制编码,64 个字符) **示例密钥:** ``` private.key: (keep secret!) public.key: 194c304f05b2d26be44f19312f25f11f7d59809d5ba258f4d19c537c7dc3b7dd ``` #### `updatesUrl` (string, 必填) 更新服务器的基础 URL。 ``` { "updatesUrl": "https://updates.yourcompany.com" } ``` **路径构建:** - 版本列表:`${updatesUrl}/releases/versions.json` - 版本元数据:`${updatesUrl}/releases/${version}/${version}.yml` - 更新文件:`${updatesUrl}/releases/${version}/${filename}` #### `updatesEnabled` (boolean, 必填) 更新系统的总开关。 ``` { "updatesEnabled": true } ``` **设置为 `false` 以:** - 禁用所有更新检查 - 适用于具有自定义更新流程的企业部署 #### `certificateAuthority` (string, 可选) 用于 TLS 验证的 PEM 编码 X.509 证书。 ``` { "certificateAuthority": "-----BEGIN CERTIFICATE-----\nMIIDXTCCAkWgAwIBAgIJAKL...\n-----END CERTIFICATE-----" } ``` **用于:** - 自签名证书(开发) - 证书固定(生产) - 自定义 CA 链 #### `allowInsecureTLS` (boolean, 可选, 默认值: false) 禁用 TLS 证书验证。 ``` { "allowInsecureTLS": true } ``` **⚠️ 警告:** 切勿在生产环境中使用!仅用于使用自签名证书的开发环境。 #### `downgradeEnabled` (boolean, 可选, 默认值: false) 启用降级功能。 ``` { "downgradeEnabled": true } ``` **启用时:** - 启动时显示版本选择 UI - 允许回滚到旧版本 - 所有降级均经过加密验证 - 安装的版本必须高于最低版本 ### 配置示例 **config/default.json:** ``` { "updatesPublicKey": "194c304f05b2d26be44f19312f25f11f7d59809d5ba258f4d19c537c7dc3b7dd", "updatesUrl": "https://localhost", "updatesEnabled": true, "allowInsecureTLS": true, "downgradeEnabled": true } ``` #### 生产环境 **config/default.json:** ``` { "updatesPublicKey": "194c304f05b2d26be44f19312f25f11f7d59809d5ba258f4d19c537c7dc3b7dd", "updatesUrl": "https://updates.yourcompany.com", "updatesEnabled": true, "certificateAuthority": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----", "downgradeEnabled": false } ``` #### 企业环境 (无自动更新) **config/production.json:** ``` { "updatesEnabled": false } ``` ## 降级支持 ### 降级如何工作 SafeUpdater 支持对以前版本进行**验证降级**,具有与升级相同的加密保证。 ### 启用降级 **配置:** ``` { "downgradeEnabled": true } ``` ## 致谢与依赖 SafeUpdater 基于以下技术构建: - **Signal Desktop (Electron updater logic)** – 核心更新逻辑 fork 并改编自 Signal 应用程序 - **[@noble/ed25519](https://github.com/paulmillr/noble-ed25519)** – Ed25519 签名 - **[got](https://github.com/sindresorhus/got)** – HTTP 客户端 - **[config](https://github.com/node-config/node-config)** – 配置管理 - **[electron](https://www.electronjs.org/)** – 桌面应用框架 - **[electron-store](https://github.com/sindresorhus/electron-store)** – 持久化存储 - **[semver](https://github.com/npm/node-semver)** – 版本解析 - **[uuid](https://github.com/uuidjs/uuid)** – 唯一标识符 - **[lodash](https://lodash.com/)** – 实用函数 - **[vitest](https://vitest.dev/)** – 测试框架 **要了解更多关于 SafeUpdater 的架构或为项目做出贡献,请查看我们的[贡献指南](./CONTRIBUTING.md)!** **为安全的 Electron 应用而用 ❤️ 制作**
标签:Ed25519, Electron, GNU通用公共许可证, MITM代理, Node.js, SHA-512, T1553.002, XML 请求, 中间人攻击防护, 代码签名, 参考实现, 安全开发, 安全机制, 完整性校验, 密码学验证, 底层编程, 文档安全, 桌面应用开发, 版本回滚, 自动更新, 自定义脚本, 自定义脚本, 自定义脚本, 软件分发安全, 软件更新器, 防篡改, 降级攻击防护