跳过主要内容

签名验证:2026年应用程序更新的安全

Learn how signature verification protects Capacitor and Electron app updates, covering cryptographic principles and CI/CD integration.

签名验证:2026年应用程序更新的安全

您的更新管道是绿色的,包在边缘可用,设备正在检查它。然后有人注意到生成的JavaScript中有一个可疑的变化。一个被破坏的构建运行器、被盗的开发者凭证或修改的工件可能已经在测试完成后将恶意负载注入到发行版中。没有 签名验证,客户端无法可靠地区分您的团队构建的捆绑包和传输过程或交付层中被攻击者修改的捆绑包。

签名更新改变了这种决定。设备在替换当前运行的code之前,会将捆绑包验证为一个可信的公钥。如果签名不匹配,更新将保持不活跃。听起来很直接,但生产故障通常发生在加密中,而不是加密内部。团队会失去密钥轮换的跟踪,错误地签署了错误的工件,应用未验证的缓存文件,或者收集的遥测数据太少,以便解释哪些设备拒绝了更新。

以下部分关注那些操作边缘,从信任模型和验证流程到CI/CD控制、事件响应和签名本身无法解决的限制。

目录

为什么签名验证可以防止灾难性更新

一个流行的Capacitor插件的CI/CD管道在发布过程的最后阶段被破坏。攻击者修改了实时更新包,添加了code,该code读取应用程序数据,并使用管道的正常交付路径发布了 artifact。设备没有看到陌生的下载域。它们看到一个等待安装的有效更新。

没有客户端的加密检查,应用程序可能会下载并执行修改后的包,直到其更新策略允许。可能的爆炸半径包括数据泄露、凭证窃取、支付流程的改变以及静默地操纵业务逻辑。调查也很痛苦。工程师必须确定哪个 artifact 被服务,哪些通道接收了它,哪些设备下载了它,哪些设备应用了它,以及恶意code是否在发布被撤回之前运行。

软件更新交付管道中恶意code注入的签名验证如何阻止的图表。

一个启用了签名验证的团队会有不同的故障模式。该应用程序下载相同的被毒害的捆绑包,计算预期的摘要,并检查附加的签名与其信任的密钥进行比较。加密检查失败,更新器拒绝激活捆绑包,事件到达安全团队之前新code运行。

生产规则: 将更新视为有害的,直到设备验证其身份和其精确字节。

保护机制只有在验证器在设备上运行,提取或激活之前,且信任的密钥不能被更新本身替换时才有效。因此,证书和密钥管理成为更新设计的一部分,而不是管理细节。使用Capacitor的团队应在他们的 证书管理过程一并记录这一界限,包括谁可以签名,密钥存放地以及客户如何了解授权的继任密钥。

现代研究已将签名验证作为可量化的工程学科进行了几十年的研究。1977年首次发表的关于离线和在线签名验证的研究后来扩展到包括HMM和FFT在内的方法。广泛引用的比较报告人类专家约为 0.5% 的假接受率和 7% 的假拒绝率,而普通人达到了 6.5% 的假接受率和 26% 的假拒绝率,如本 签名验证研究历史综述那些数字是关于手写签名,而不是软件更新,但它们强调了一个有用的观点:验证质量取决于验证器、其参考数据和其决策策略。

加密签名如何创建信任

想象一下一个发布包就像一个密封的信封。构建系统计算了精确字节的摘要,并使用一个 私钥 来创建一个数字签名,覆盖了摘要。应用程序包含,或者安全地接收了,相应的 公钥,它像信封上的已知徽章一样起作用。如果攻击者改变了包的一小部分,应用程序计算了一个不同的摘要,签名不再验证。

一个图表,展示了从开发人员创建签名到移动应用程序验证的加密签名过程。

流程有四个不同的部分:

  1. 散列 将包转换为固定长度的摘要。SHA-256和SHA-512是此完整性步骤的常见选择。
  2. 密钥生成 生成一个非对称对。私钥签名,公钥验证。
  3. 签名 将摘要绑定到发布元数据中,理想情况下包括版本、渠道、平台和受众。
  4. 验证 重新计算从下载的字节中计算的摘要,并检查签名是否由受信任的私钥产生。

验证器必须将签名绑定到将要应用的相同负载上。对清单的签名不足以证明应用后下载的包的清单的哈希与包匹配。同样,验证包的哈希并不能证明它是谁授权的,除非哈希本身是经过身份验证的。

选择移动端传递算法

RSA仍然熟悉且广泛支持,但它通常需要更大的密钥材料和谨慎的填充选择。对于新移动端更新协议,Ed25519经常是有吸引力的,因为其密钥和签名是紧凑的,其验证路径在移动处理器上是高效的。RSA-PSS也可以在兼容性要求使RSA成为必要时适当。选择应该遵循平台加密库、支持硬件、互操作性要求和迁移计划,而不是从另一个环境中复制的benchmark。

一个有用的独立介绍是关于 理解区块链中的加密签名。交易上下文与OTA传递不同,但私钥授权和公钥验证的说明直接转移了。

信任链和固定密钥

A 证书链将信任从根证书通过中间机构传递到叶证书。该模型可以简化广泛的PKI操作,但应用程序更新客户端通常有一个更窄的要求:只信任授权此更新的发布者密钥。将公钥或一小组授权密钥直接嵌入应用程序二进制文件是一种固定密钥的形式。它减少了对外部证书机构的依赖,但它会创建一个轮换问题,因为二进制文件必须已经信任替换密钥。

Keep the signed envelope complete. Your release metadata should identify the artifact, its digest, the intended channel, and the key identifier. Teams building this into Capacitor can use a focused token-signing checklist for Capacitor apps 用于__CAPGO_KEEP_0__应用程序

在发布前检查密钥范围、存储和验证边界。

Signature verification appears in several layers of a mobile product, and each layer answers a different question. App-store signing helps the operating system decide whether an installable package comes from an authorized publisher. A signed OTA bundle answers whether the JavaScript and asset payload came from the release authority your updater trusts. A JWT signature helps an API validate that a token was issued by the expected identity service.

混淆这些层次会造成缺口。有效的IPA签名并不能自动验证后续的Web包。有效的JWT并不能证明更新包是安全的。TLS连接保护了传输,但它并不能代替艺术品签名,当CDN、代理、缓存或构建系统成为窃听者的源头时。

上下文 签名机制 防止的失败模式 常见的缺口
应用商店包 平台code签名和平台审查控制 重新签名或未经授权的可安装包 团队假设商店签名覆盖了安装后Web资产
Web包和服务工作者 签名交换或SRI风格完整性引用 被中毒的CDN响应或修改的资产 只有入口文件被检查,而导入的资产仍未被验证
API令牌 使用可信的公钥验证 JWT 签名,通常通过 JWKS 端点获取 伪造或篡改的令牌 服务器验证签名,但忽略发行者、受众、过期时间或令牌目的
无线更新 设备上分离或嵌入的包签名验证 中间人或篡改的更新注入 客户端下载、缓存或解包内容之前,才会执行决策

对于 Web 资产,子资源完整性可以限制浏览器接受的资源,但它并不能自动解决动态导入、服务工作者缓存或指向攻击者选择文件的更新清单。实现必须定义完整的 artifact 集合并验证将执行的字节。

JWT 部署会以不同的方式失败。工程师经常发布正确的公钥,但接受令牌的错误发行者或受众,或者他们信任令牌头部提供的算法选择。加密签名可以是有效的,而授权决策仍然是错误的。

产品依赖于频繁发布和客户端面向的移动体验的运营上下文也很重要。评估 2026 年零售应用参与度策略 应将更新完整性视为快速实验的先决条件。快速发布仅在发布渠道、工件和接收者都与同一授权决策绑定时才有用。

构建完整的验证流程

生产更新程序应将验证作为门槛,而不是在安装时远程执行的回调。安全序列是确定性的:

  1. 通过已验证的传输方式获取清单和签名。
  2. 验证清单结构、版本策略、渠道、过期时间和工件身份。
  3. 下载清单中命名的精确工件。
  4. 在本地计算工件的摘要。
  5. 使用可信的Ed25519或RSA-PSS公钥验证签名。
  6. 将已验证的工件存储在隔离的位置。
  7. 原子性地应用它,然后保留回滚路径。

四步图表,展示了软件更新包的获取、签名验证和验证过程。

manifest必须绑定所有影响决策的值。至少,意味着捆绑摘要、版本、频道、平台和密钥标识符。不要让下载器在验证后替换URL、文件名或频道。验证器应接收不可变字节和不可变元数据,然后返回一个单一的接受或拒绝结果。

一个简化的TypeScript形状看起来像这样:

type UpdateManifest = {
  version: string
  channel: string
  platform: string
  sha256: string
  signature: string
  keyId: string
}

async function verifyBundle(
  bundle: Uint8Array,
  manifest: UpdateManifest,
  trustedKeys: Map<string, Uint8Array>
): Promise<boolean> {
  const publicKey = trustedKeys.get(manifest.keyId)
  if (!publicKey) return false

  const digest = await sha256(bundle)
  if (!constantTimeEqual(digest, hexToBytes(manifest.sha256))) {
    return false
  }

  try {
    return await ed25519Verify(
      base64ToBytes(manifest.signature),
      digest,
      publicKey
    )
  } catch {
    return false
  }
}

示例故意严格。基64编码错误、未知密钥标识符、摘要不匹配或签名失败都应产生拒绝。下载超时不是应用之前部分文件的理由。删除不完整的工件、保留最后一个已知良好版本,并在有界策略下重试。

防止竞争和回滚错误

下载到临时路径。关闭并刷新文件,验证其完整内容,然后将其重命名为版本化的已验证存储。激活步骤应仅引用已验证的路径。在Capacitor和Electron环境中,避免让异步下载完成事件触发激活独立于验证承诺。一个单一的更新状态机应拥有像、和这样的转换。 downloading, verified, pending, active, rejected, rolled_back.

对于敏感字节序列的比较,适时的恒等比较是合适的,尤其是攻击者可以观察到重复验证行为。从运营的角度更重要的是,不要暴露接受一个捆绑包的捷径,因为之前的尝试标记了版本为可用。可用性和真实性是两个独立的状态。

The Capacitor 更新的完整性检查 是一个有用的实现参考,用于将哈希验证和激活逻辑区分开来。测试故障分支,包括截断文件、损坏的签名、未知密钥、过时的清单、重复版本和激活过程中终止的进程。

自动签名验证研究表明,阈值和参考数据在其他领域也很重要。1994 年的一项在线研究测试了 22 个特征,选择了最好的 10,并报告了 99.5% 正确分类真实签名,同时拒绝 86% 的伪造签名 ,根据发表的统计方法研究

管理密钥的挑战,大多数团队都低估了

第一个签名密钥很容易。第二个密钥是体系结构被测试的地方。

一支团队可以生成一个密钥对,将公钥放入应用程序中,并在一天内签署其第一个捆绑包。几个月后,一名工程师离开了,拥有对笔记本电脑的访问权限,CI机密被打印在构建日志中,或签名任务需要从一个运行器转移到另一个。到那时,“只需旋转密钥”可能意味着放弃那些无法识别替换密钥的设备。

一个比较图表,展示了简单一次性密钥设置与复杂的生产现实之间的差异。

在首次发布之前,应关注三个问题:

  • 无死角的旋转: 在要求使用新密钥之前,先将信任的继任密钥交付给应用程序。一个已签名的密钥转换记录可以让一个已信任的密钥授权下一个密钥,而应用程序在一个定义的迁移窗口内继续接受旧密钥。
  • 无假设的撤销: 一个内嵌在应用程序中的密钥并不自动提供OCSP或CRL样式的撤销。客户端需要一个已签名的拒绝列表,一个最低可接受的密钥版本,或一个由服务器控制的政策,即使网络不可用时也保持安全。
  • 受限的签名访问: CI 运行器应从保管库或 HSM 请求签名操作,而不是接收可重用的私钥作为平文环境变量。日志必须对命令输出进行抹黑,来自不受信任分支的拉取请求不得到达生产签名凭证。

运营现实: 密钥轮换是一个更新问题。如果更新机制无法安全地交付信任变化,它就无法从被破坏的密钥中清洁恢复。

密钥层次结构减少了爆炸半径。根权威可以授权发布密钥,而单独的密钥则签署开发、测试和生产通道。阈值签名可以要求多个授权方在敏感生产发布中签署,这有助于防止一枚被盗的凭证创建有效的更新。这些控制会增加过程和延迟,因此团队应根据更新的影响和通道的敏感性来应用它们。

首次使用的信任尤其脆弱,尤其是在移动更新中。如果第一个密钥通过与包相同的通道传递,攻击者可以控制该通道的攻击者可以替换两个。初始信任锚必须通过应用二进制、平台保护的配置或其他独立验证的路径传递。

对于 Capacitor 团队,Capgo 的文档方法包括公钥固定和密钥轮换支持。 安全 OTA 更新的密钥管理指南 提供了一个实用的参考,用于规划密钥生命周期,而不是将密钥生成视为一次性设置。

CI/CD 和监控中集成验证

发布应该包含在发布事务中。管道不应首先发布一个包,然后在一个单独的手动步骤中附加其签名。构建不可变的艺术品,计算其摘要,签署精确的字节,使用干净的验证步骤验证签名,并以一个发布单元的形式发布包和元数据。

实用的管道产生这些艺术品:

  • 不可变的包: 客户端将下载的文件,而不是 CDN 将重新打包的目录。
  • 清单: 版本、渠道、平台、摘要、密钥标识符和发布策略。
  • 脱离的签名: 对规范清单数据或精确定义的摘要表示的签名。
  • 验证结果: 机器可读的检查,签名是否验证了预期的环境中的公钥。

GitHub Actions 和 GitLab CI 可以通过不同的语法强制执行相同的模式。签名工作应该失败,如果私钥签名服务不可用,如果签名有误,如果下载的测试副本没有验证。部署工作应该依赖于该结果,而不是仅仅依赖于成功的构建。

不要在签名路径后允许后续任务修改它。签名后锁定工件,发布前比较其摘要,并从发布记录中重现发布清单。这可以捕捉到一个意外的集成缺口,CI任务签名一个压缩存档,而交付层则服务一个重新压缩或重新生成的文件。

可观察性应位于设备上

成功的签名任务只证明了管道创建了一个有效的签名。它并不能证明设备接收了预期的字节或应用使用了预期的密钥。记录应用版本、更新版本、渠道、平台、密钥标识符、结果类别和隐私安全的发布关联ID。避免记录包、令牌、私有元数据或用户内容。

有用的仪表板分离:

  • 签名失败与下载失败
  • 摘要不符与不良的清单
  • 未知密钥与政策拒绝
  • 根据应用版本、区域、渠道和发布年龄的失败

突然出现的摘要不符事件可能指示缓存被损坏、交付路径被修改或工件发布错误。未知密钥事件可能指示轮换不完整或未经授权的发布尝试。验证指标本身无法识别攻击者,但它为响应者提供了时间线和调查对象。

关于__CAPGO_KEEP_0__ OTA更新的CI/CD安全指南 CI/CD security guidance for Capacitor OTA updates 可以帮助团队在一个工作流中放置签名、验证和部署门控。重要的设计选择是所有权。安全性不应需要向工程团队询问是否进行了验证。发布记录和客户端遥测应该直接回答这个问题。

安全最佳实践和常见陷阱

签名验证应该成为每个可以执行code的更新路径的硬性要求。更新器必须在提取、安装或激活之前验证,且在签名、摘要、密钥或策略检查不可用时必须失败。

请立即使用以下检查清单:

  • 保护私钥: 将签名材料存储在HSM或托管的安全存储器中。绝不将其提交到源代码控制、放入移动二进制文件或允许进入CI日志。
  • 固定可信的公钥: 将初始信任锚点存储在更新负载之外。如果您支持多个密钥,请定义其目的和过渡规则。
  • 绑定完整的发布: 签名可识别发布的元数据,包括确切的包、通道、平台和预期策略。
  • 拒绝每个验证错误: 超时、签名格式错误、未知密钥或缺失的清单不是继续使用未验证的结果的邀请。
  • 测试恢复机制: 在测试环境中,进行密钥轮换、失效密钥处理、回滚、中断下载和陈旧设备的测试。
  • 审查验证器变更: 要求对加密库、规范化、解析、回退行为和调试配置进行安全性相关的code审查。
  • 保持调试行为隔离: 开发环境的绕过必须无法通过默认标志或环境错误打包到生产构建中。

签名也不能证明最新性、接收方绑定、重放抵抗或载荷与提供者的当前状态兼容性。 webhook 安全指南清晰地指出这一点,最近的漏洞报告表明,错误或空签名和规范性问题仍然可以破坏狭窄的验证检查。 在设计周围的授权规则时,请阅读 webhook 安全性差距分析。

阈值选择会在生物识别系统中产生相关的教训。 一项使用 62 个参数特征1,232 个签名中 来自 102 名个体的签名中报告了写者依赖的阈值 2.8% 的伪拒绝率1.6% 的伪接受率, 另一方法报告 2.68% 的伪拒绝率1.99% 的伪接受率, 如文档中所述 阈值选择研究. 应用程序不同,但操作原理相同:验证器的决策策略与密码学原语一样重要。

Capgo 可以作为 Capacitor 和 Electron 团队需要签名的实时更新包、设备端验证、发布控制、回滚保护和交付可观察性在同一系统中的一个实现选项。访问 Capgo 评估其更新流程是否符合您的密钥管理、CI/CD 和监控需求。

实时更新Capacitor应用

当web层bug处于活跃状态时,通过Capgo将修复部署,而不是等待几天的应用商店审批。用户在后台接收更新,而本机更改保持在正常审批路径中。

来自马丁的人性化支持

立即开始

最新博客文章

Capgo为您提供创建真正专业的移动应用所需的最佳见解。