安全指南

winapp CLI 使本地Windows开发变得非常简单:它可以生成签名证书,在计算机上信任它,并为你启用开发人员模式。 每个步骤都会更改计算机状态或创建一个包含私钥的文件,因此它有助于确切地了解它们执行的操作。

本页说明了每条命令的后果、如何撤销它,以及在发布时应该采取哪些不同的做法。 开发证书和开发人员模式是本地测试的正常、受支持的路径, 此处的目标是了解你选择的内容,而不是避免它们。

开发证书

必须先对 MSIX 包进行签名,然后Windows才能安装它们。 在本地测试时,winapp cert generate 会创建一个自签名证书,这样你无需购买任何东西即可为自己的包签名并安装。

winapp cert generate 创建的内容

生成的证书是自签名的端到端代码签名证书:

财产 值
Key RSA 2048 位,标记为可导出
签名算法 SHA-256 与 RSA (PKCS#1 v1.5)
密钥用法 数字签名
增强型密钥用法 代码签名 (1.3.6.1.5.5.7.3.3)
基本约束 不是证书颁发机构
有效性 默认情况下为 365 天(--valid-days)
Subject 必须与清单文件中的 Publisher 匹配

该命令写入两项内容:

  • devcert.pfx 在当前目录中(或传递给 --output的路径)。 此文件同时包含证书及其私钥。
  • 个人证书存储区中的证书副本(Cert:\CurrentUser\My)。

使用 --export-cer时,它还将文件 .cer 写入到该文件 .pfx旁边。 该文件仅包含公钥证书——不含私钥——因此很适合交给团队成员,或交给需要信任你的构建产物的测试机器。

注释

在有人明确信任证书之前,没有人信任自签名证书。 它适用于自己的计算机和你自己的测试计算机;分发应用时,它不能替代真正的代码签名标识。

默认密码

winapp cert generate 使用 --password 作为 PFX 密码,除非你传递了 password。 当你稍后将该证书提供给 --password 时,同样的默认值也适用;其密码选项同样为 winapp pack。对于 --cert-password 也是如此,它接受 winapp sign。

众所周知的密码意味着私钥 devcert.pfx 实际上不受保护, 任何获取该文件的人都可以使用它对代码进行签名。 对于仅用于给你自己机器上的本地测试构建签名的一次性证书来说,这种权衡是可以接受的,这也是之所以会有这一默认设置的原因。

Important

将默认密码视为证书可释放的信号。 如果证书曾经用于对另一个人安装的内容进行签名,则它不应是 winapp cert generate 具有默认密码的证书, 请参阅 “为生产签名”。

脚本和代理无需自行比对密码:当默认值生效时,winapp cert generate --json 会报告 "defaultPasswordIsPublic": true,并在 warnings 数组中重复该披露信息。 请参阅 证书生成 JSON 输出。

证书文件所在的位置

devcert.pfx 是磁盘上的私钥。 两个规则使它摆脱了麻烦:

不要提交它。winapp cert generate 自动将证书的文件名追加到 .gitignore 它的旁边,因此已涵盖默认流。 如果移动文件、重命名文件或将其生成到由其他 .gitignore管理的目录中,请检查其后面的条目:

git check-ignore -v devcert.pfx

如果没有输出任何内容,则该文件未被忽略——请在提交前先添加该文件。

不要打包它。winapp pack 会打包输入目录中的所有内容,因此,位于应用输出文件夹中的 devcert.pfx 最终会被打进交付的 MSIX 包中。 按照 打包 EXE/CLI 指南 所示,在你要打包的文件夹之外生成证书,并在分发之前确认该文件夹中没有该证书:

# Unpack the package and check that no certificate is inside
winapp tool makeappx unpack /p .\MyApp.msix /d .\inspect /o
Get-ChildItem .\inspect -Recurse -Include *.pfx, *.cer

Tip

如果带有真实私钥的 .pfx 确实被提交或发布了,请立即进行轮换:生成新证书、重新签名,并按照 删除受信任的证书 中的步骤停止信任旧证书。 从以后的提交中删除文件不会将其从历史记录中删除。

winapp cert install 授予的权限

winapp cert install 将证书添加到存储区 LocalMachine\TrustedPeople 。 这需要管理员权限,因为它会更改计算机上每个用户的信任。

证书位于TrustedPeople中后,Windows 会将由该证书签名的任何 MSIX 包都视为受信任到足以安装,而不只是你当时测试的那个包。 对于其私钥由你持有并保存在本地的证书,这恰恰是预期的结果。 这也是为什么要慎重对待此事:

  • 信任你自己生成的证书,或者来自你将在计算机上安装软件的人。
  • 不要在其他人依赖的共享、生产或生成计算机上安装开发证书。
  • 当同事需要安装你的测试包时,优先分发 .cer(仅公钥),而不是 .pfx。 他们可以信任你的构建产物,而无须获得以你的身份签名的能力。

若要在另一台测试计算机上信任.cer,请直接在该机器上运行winapp cert install——该命令既接受.cer,也接受仅包含公钥的.pfx:

# Run as Administrator
winapp cert install .\devcert.cer

仅使用内置Windows工具的等效项是:

# Run as Administrator
Import-Certificate -FilePath .\devcert.cer -CertStoreLocation Cert:\LocalMachine\TrustedPeople

删除受信任的证书

默认情况下,开发证书会在一年后过期,但过期并不意味着证书会被移除。 当你不再需要某个证书时——例如项目已结束、机器被改作他用,或者密钥可能已经泄露——请明确将其删除。

首先,找到其指纹:

Get-ChildItem Cert:\LocalMachine\TrustedPeople |
    Where-Object { $_.Subject -like '*CN=Contoso*' } |
    Format-List Subject, Thumbprint, NotAfter

然后将其从计算机信任存储中删除。 此步骤需要提升权限:

# Run as Administrator. Replace with the thumbprint from the previous command.
$thumbprint = 'ABCD...'
Remove-Item -Path "Cert:\LocalMachine\TrustedPeople\$thumbprint"

cert generate 还将该证书及其私钥放入你的个人存储区。 在一个 普通、非提升权限的命令提示符中,以运行了 cert generate 的帐户身份登录,然后移除该项:

$thumbprint = 'ABCD...'
Remove-Item -Path "Cert:\CurrentUser\My\$thumbprint"

Important

在显示的上下文中运行上述两个命令。 如果你是使用其他管理员账户以提升的权限运行的,那么在该提升权限会话中,Cert:\CurrentUser 指的是该管理员的证书存储,而不是你的,因此私钥会保留在生成该密钥的用户的证书存储中。

最后,删除你分发出去的 .pfx 以及任何 .cer 副本,并取消注册你用它旁加载的包:

winapp unregister

注释

删除证书不会卸载已安装的包。 请分别通过“设置”>“应用”>“已安装的应用”卸载这些项,或对以开发模式注册的软件包使用winapp unregister。

开发人员模式

Windows 需要启用开发者模式,才能直接从磁盘上的文件夹注册应用包——即松散布局——而不是安装已生成并签名的 MSIX 包。 诸如 winapp run 和 create-debug-identity 这样的命令都依赖它,没有它就会失败,而 winapp init 会提示为你启用它。

启用后会发生哪些变化

CLI 通过在 HKEY_LOCAL_MACHINE 下写入两个 DWORD 值来启用开发者模式:

HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock
    AllowDevelopmentWithoutDevLicense = 1
    AllowAllTrustedApps               = 1

由于这些是系统范围的设置,CLI 会启动一个提升权限的辅助进程,而 Windows 会显示用户帐户控制提示。 如果拒绝提示,则不会更改任何内容。

实际上,这意味着计算机将:

  • 直接从磁盘上的文件夹注册应用包,无需将其打包为 MSIX,也无需进行签名(AllowDevelopmentWithoutDevLicense)。
  • 只要应用包已由该计算机信任的证书签名(包括 AllowAllTrustedApps 中的任何开发证书(TrustedPeople)),就可以从 Microsoft Store 外部安装应用包。

Important

开发人员模式加上受信任的开发证书是默认安装限制的故意松动。 这种组合适用于开发和测试机器。 在生产环境中的机器、自助终端和共享基础设施上,请保持将其关闭。

控制启用时间

winapp init 会在进行任何更改前先询问,而 --use-defaults 则会完全跳过询问,使开发者模式保持不变。 这使得脚本化和 CI 默认运行安全:

winapp init --use-defaults

如果希望自行管理设置,请通过 “ > 设置系统 > 为开发人员 > 开发人员模式 ”启用一次,CLI 将检测并继续操作。

将其关掉

依次进入设置 > 系统 > 开发人员选项,然后关闭开发人员模式。 这是建议的路径,因为“设置”也会清理关联的 OS 状态。 若要在随后确认注册表值,请执行以下操作:

Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock' `
    -Name AllowDevelopmentWithoutDevLicense, AllowAllTrustedApps

关闭开发人员模式不会删除受信任的证书或已安装的包 - 请参阅 “删除受信任的证书”。

为生产用途签名

开发证书仅对已明确表示信任该证书的用户有效。 若要分发应用,请使用Windows已信任的标识对其进行签名。

选择签名身份

  • Azure 受信任签名 - 云托管的签名服务。 私钥永远不会存在于你的构建计算机上,因此无需保护、泄露或手动轮换 .pfx。 使用 winapp az-sign,它使用标准Azure凭据链进行身份验证,并适用于 GitHub Actions OIDC 或托管标识。

    winapp az-sign .\MyApp.msix
    
  • 来自受信任的证书颁发机构的代码签名证书 , 将其 winapp sign 作为第二个位置参数传递给,并在其中输入密码 --password。 然后,你负责安全地存储密钥材料;将其保存在硬件令牌、密钥保管库或 CI 提供程序的机密存储中,并且永远不会保留在存储库中。

  • Microsoft Store - 如果你专门通过应用商店分发,它会为你签名程序包,并且无需在提交之前进行签名。

在所有情况下,证书主题都必须与你的清单中的 Publisher 值匹配,包括稀疏包。

不要将签名密钥保存在代码仓库中

证书密码属于 CI 机密存储,不在配置文件中。 从环境中读取它们,而不是对它们进行硬编码:

winapp sign .\MyApp.msix $env:SIGNING_CERT_PATH --password $env:SIGNING_CERT_PASSWORD

这同样适用于签入源代码控制的构建配置,例如 Electron Forge 配置——请参阅 Electron 打包。 winapp az-sign 彻底避免了这个问题,因为没有需要传递的密码。

发布之前

从本地测试过渡到分发的简短清单:

  • 该包使用 CA 颁发的证书、Azure 受信任签名进行签名,或提交到 Microsoft Store,而不是使用 devcert.pfx。
  • 打包的输出中没有 .pfx 文件或 .cer 文件。
  • 提交的文件、生成脚本或 CI 日志中未显示证书密码。
  • 证书主题与清单 Publisher 匹配。
  • 开发证书和开发人员模式在只需 运行 应用的计算机上未启用。

报告安全问题

若要报告 winapp CLI 本身中的安全漏洞,请遵循 SECURITY.md 中的过程。 请不要通过公开的 GitHub Issue 提交安全问题报告。