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 请求, 中间人攻击防护, 代码签名, 参考实现, 安全开发, 安全机制, 完整性校验, 密码学验证, 底层编程, 文档安全, 桌面应用开发, 版本回滚, 自动更新, 自定义脚本, 自定义脚本, 自定义脚本, 软件分发安全, 软件更新器, 防篡改, 降级攻击防护