ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Viap 应用迁移工具发布签名与完整性校验:GitHub Release + Minisign 全流程拆解

Viap 应用迁移工具发布签名与完整性校验:GitHub Release + Minisign 全流程拆解

【免费下载链接】viap

Windows application management and data migration tool.

项目地址:https://gitcode.com/gh_mirrors/vi/viap
点击查看免费下载

Viap 是一款 Windows 应用管理与数据迁移工具(Tauri + React + Rust 构建)。它通过 GitHub Release 发布安装包,并使用 Minisign 数字签名与完整性校验机制,确保用户下载的迁移工具没有被篡改。本文完整拆解这条“发布签名 → 上传签名 → 运行时校验”的安全链路,帮助新手理解一个桌面工具是如何自证清白的。

为什么迁移工具需要发布签名?

应用迁移工具会读写大量用户数据,对“程序本身是否可信”的要求比普通工具更高。Viap 的威胁模型很简单:

  • 用户从非官方渠道下载了被植入后门的安装包;
  • 下载链路被中间人替换文件;
  • 本地文件在存放过程中被恶意修改。

对应的防御手段就是发布签名 + 完整性校验:

  1. 发布方用 Minisign 私钥对每个发布产物签名,生成.sig文件;
  2. 公钥内置在程序里,任何拿到程序的人都能验证“文件确实是官方签过的”;
  3. 程序运行后还能主动从官方发布页拉取签名,复核自身文件是否被改动过。

这套机制由三部分协作完成:发布流水线、签名密钥配置、运行时校验模块。

密钥对管理:私钥在 Secrets,公钥在配置里

🔑 签名体系的关键在于私钥永不出现在仓库中:

密钥存放位置用途
Minisign 私钥GitHub 仓库的TAURI_SIGNING_PRIVATE_KEY/TAURI_SIGNING_PRIVATE_KEY_PASSWORD两个 Secrets发布流水线签名用
Minisign 公钥tauri.conf.json 的updater.pubkey字段(Base64 文本)自动更新与完整性校验

tauri.conf.json 中还配置了createUpdaterArtifacts: true(第34行),让 Tauri 在构建时自动生成供自动更新器使用的签名产物;而updater.endpoints指向 GitHub Release 上的latest.json,即“当前最新版本”的清单文件。

运行时校验模块 src-tauri/src/integrity/mod.rs 中同样硬编码了同一把公钥,并明确注释:该公钥必须与tauri.conf.json的updater.pubkey保持一致,避免完整性校验使用另一把密钥。校验能力依赖 Cargo.toml 中的minisign-verify(Minisign 签名解析与流式校验)与reqwest(仅启用 rustls,避免引入系统 TLS 依赖)两个依赖。

GitHub Release 签名流水线:release.yml 全流程

整个发布流程由 .github/workflows/release.yml 驱动,分为release与release-extras两个 Job。

版本号 Tag 触发构建

流水线在推送到v*前缀的 Tag 时自动触发,也支持手动指定 tag 执行(release.yml 第3-12行)。一个贴心细节:发行说明不是手工填写的,而是直接从 CHANGELOG-zh.md 中提取当前版本段落,找不到对应段落时才退回最新版本段并告警(release.yml 第59-100行),避免发版时再手工抄一份更新内容。

tauri-action 自动构建并签名

核心构建步骤使用官方tauri-apps/tauri-action@v0.5(release.yml 第102-113行):

  • 从 Secrets 注入私钥环境变量,完成标准 NSIS 安装包的签名;
  • 自动在 GitHub 上创建 Release,上传安装包、签名文件和latest.json;
  • 签名产物随附.sig文件,用户可随时下载自行复核。

原始 exe 的签名与 NSIS 标记坑

这是整套流程中最容易踩坑的一步。完整性校验的对象是当前正在运行的 exe,而 Tauri 打包后,安装器安装到磁盘的 exe 与编译产物并不是逐字节相同的:NSIS 会把 Tauri 主程序中的 bundle 类型标记从__TAURI_BUNDLE_TYPE_VAR_UNK改写为__TAURI_BUNDLE_TYPE_VAR_NSS。

因此 CI 在签名前会执行 scripts/prepare-integrity-exe.ps1:

  • 先校验 exe 中 bundle 标记唯一存在,发现多个直接拒绝签名(第19-24行);
  • 由于两个标记字符串等长,只替换标识文本,不改变 PE 布局与文件长度(第26-30行);
  • 处理后,签名覆盖的才是安装后实际运行的字节。

这一步对应 CHANGELOG 中 v1.1.9 的修复记录(CHANGELOG.md 第53-55行):“Fixed release signing for NSIS installers after Tauri bundle processing”。

额外发行包:离线安装包与便携版

release-extrasJob 产出两种补充形态并逐一签名(release.yml 第152-240行):

  • WebView2 离线安装包:使用 tauri.offline-webview2.conf.json 构建,内置离线安装运行环境,适合无法联网的电脑;
  • 便携版 ZIP:以--features portable --no-bundle编译原始 exe,附带说明文本打包为 zip,数据默认存放在程序目录下data文件夹。

值得注意的是,CI 注释中明确说明:额外发行包不参与 updater 的latest.json,避免便携版或离线安装包被误当成自动更新目标。

应用内“校验文件完整性”:校验流程拆解

用户在设置页点击“校验文件完整性”后(Settings.tsx 第369-382行),前端调用后端命令verify_file_integrity,核心逻辑在 integrity/mod.rs 的 verify_file_integrity:

  1. 定位基准:用 Tauri 包信息取当前版本号,拼出v版本号作为 Release tag,定位当前版本对应的官方发布;
  2. 下载签名:只下载三种发行形态的.sig文本文件(x64.exe、x64-offline-webview2.exe、x64-portable.exe,见第18-19行),而不是重复下载几百 MB 的安装包;
  3. 解析签名:Tauri signer 上传的.sig是“外层 Base64 + 内层 Minisign 文本”双层结构,decode_signature_content 会先按标准格式尝试解析,失败后再做 Base64 解码,两种格式都兼容;
  4. 流式校验:verify_local_file 让所有候选签名共享同一次本地文件读取(1 MB 缓冲逐块喂给各 verifier),避免大文件在机械盘上被重复读取。文件读取还可能持续数秒,因此放入阻塞线程池执行(第264-268行),不拖住 Tauri 异步运行时。

错误分类:宁缺毋滥的判定原则

⚠️ 这套设计最值得学习的是错误分类(IntegrityStatus 枚举):

状态含义
verified签名与文件内容完全一致
tampered签名匹配失败,文件可能已被篡改
network_error连不上发布服务,不判定篡改
signature_not_found未找到签名或签名不全,不判定篡改
signature_invalid签名文件本身格式异常
local_file_error/configuration_error本地文件读取失败 / 公钥配置错误

两处细节体现了严谨性:

  • 签名不全 ≠ 篡改:三种发行形态的签名缺任何一个时,返回signature_not_found而不是tampered(第255-262行),避免把“发布渠道缺文件”误报成安全事件;
  • 测试兜底:模块自带单元测试(第300-315行),用真实 Tauri signer 格式样本防止“把外层 Base64 当成 Minisign 文本”这类回归。

与自动更新渠道的协同

签名体系同时服务于自动更新链路:

  • 安装版:tauri-plugin-updater按 tauri.conf.json 的 endpoint 拉取latest.json检查更新,下载的新包同样由公钥验签后才安装;前端逻辑封装在 src/hooks/useUpdater.ts;
  • 便携版:不注册 updater 插件(lib.rs 第378-380行),改由 portable_update.rs 查询最新发布版本,只在真的存在更高版本时才提示手动下载;其版本比较按数字段逐段解析(第52-61行),避免了字符串比较把1.10.0判成小于1.9.0的经典错误;
  • 一致性约束:portable_update.rs注释明确要求版本比对接口必须与完整性校验指向同一个仓库(第14-18行),否则校验与更新各说各话。

小结:这套发布安全链路给了什么启示

  1. 私钥进 Secrets,公钥进配置,仓库本身永远拿不到签名能力,CI 之外无法伪造发布;
  2. 签名对象要“所见即所得”:NSIS 打包会改写 exe 内部标记,签名前必须把待签文件对齐到安装后真实字节;
  3. 安全判定要做错误分类:网络失败、签名缺失与文件篡改是三种完全不同的结论,混为一谈会制造恐慌式误报;
  4. 大文件校验讲效率:只下载几 KB 的.sig、共享一次文件读取、阻塞 IO 下沉线程池,安全功能也可以很轻。

想进一步了解完整性校验的用户侧行为,可参考 README.zh-CN.md 的“文件完整性校验”章节;签名相关的版本演进记录见 CHANGELOG.md 中 v1.1.6(新增发行产物完整性校验)、v1.1.8(改进签名产物校验)与 v1.1.9(修复 NSIS 签名)三条记录。

【免费下载链接】viap

Windows application management and data migration tool.

项目地址:https://gitcode.com/gh_mirrors/vi/viap
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进