
1. 为什么我们需要一个免费的代码签名证书如果你是一个独立开发者或者在一个小团队里鼓捣一些Windows上的小工具、脚本或者开源项目那你大概率遇到过这个场景辛辛苦苦写好的程序发给朋友或者用户对方双击运行时Windows Defender或者SmartScreen会弹出一个刺眼的警告——“Windows已保护你的电脑”。更糟的情况是直接被杀毒软件当成病毒给隔离了。用户一脸懵你也百口莫辩。这个问题的根源很大程度上是因为你的程序没有经过“代码签名”。你可以把代码签名想象成软件的“身份证”和“公章”。微软作为Windows系统的“房东”它更信任那些有正规“身份证明”即由受信任的证书颁发机构签发的代码签名证书的软件。没有这个签名你的软件就是个“三无产品”系统自然要提高警惕。对于个人或小项目来说购买商业代码签名证书是一笔不小的开销动辄每年几百到上千美元而且通常有效期只有1-3年。这对于非商业、学习或者开源项目来说成本太高了。所以“完全免费的Windows代码签名证书”这个需求就变得非常真实和迫切。它不是为了替代商业证书在严格商业环境下的作用而是为广大的个人开发者、学生、开源贡献者提供一条降低用户使用门槛、提升软件可信度的可行路径。今天要聊的就是围绕这个目标梳理目前社区内可行、可靠的几种免费代码签名方案。我会详细拆解它们的原理、适用场景、具体的操作步骤以及最重要的——它们各自的局限性和你可能遇到的“坑”。我们的目标很明确在不花钱的前提下尽可能让我们的Windows程序跑得更“体面”一些。2. 免费代码签名的核心思路与分类在深入具体方案之前我们必须先理解Windows代码签名的信任链。整个体系就像一个金字塔根证书位于顶端由微软内置在Windows系统中。全球只有少数几家受信任的根证书颁发机构CA如DigiCert、Sectigo等。中间证书由根证书机构签发用于实际签发终端实体证书。代码签名证书终端实体证书我们最终用来给软件签名的证书由中间证书签发。商业证书走通了整个链条你向CA付费 - CA验证你的身份 - 签发给你一个由其中间证书签名的终端证书 - 你的软件用该证书签名 - 系统验证签名链直至受信任的根 - 放行。免费的方案都无法获得由微软内置根证书直接信任的CA签发的证书。因此所有免费方案的思路都是“曲线救国”主要分为三大类2.1 类一使用开源项目提供的免费证书如SignPath或Certum的免费个人证书这类是目前最接近“正规军”的免费方案。某些CA为了推广或支持开源社区会提供有限制的免费代码签名证书。原理CA本身是受信任的但其签发的这种免费证书可能带有特定扩展属性如1.3.6.1.4.1.311.20.2.2-szOID_ENHANCED_KEY_USAGE_CODE_SIGNING或者其对应的根证书/中间证书并非被所有Windows版本默认信任。有时需要用户手动安装根证书。优点签名流程标准使用标准工具如signtool.exe即可。在某些配置下能有效消除“未知发布者”警告。缺点申请流程可能繁琐需要验证GitHub项目等证书有效期短通常1年续期不稳定且最大的问题是信任范围有限。它可能只在安装了特定根证书的机器上有效对于广大普通用户而言警告可能依然存在。2.2 类二利用Windows内核驱动签名机制ESD这是一个非常特殊且技术要求高的领域通常用于硬件驱动开发。原理微软为硬件开发者提供了一种免费的“扩展验证驱动签名”EV Code Signing的替代方案即提交驱动到Windows硬件开发者中心门户进行签名。签名的对象是.cab包内的.cat文件。优点最终获得的签名是由微软直接颁发的兼容性极佳。缺点仅适用于内核模式驱动.sys文件绝不适用于普通的用户态.exe或.dll。申请需要注册微软合作伙伴中心账户流程复杂。这完全不是为普通应用程序准备的方案误入此途只会浪费时间。2.3 类三自签名证书 引导用户安装证书这是最灵活、也是最需要用户配合的方案。原理自己用工具如OpenSSL,MakeCert.exe,New-SelfSignedCertificatePowerShell命令生成一个证书。用这个证书给软件签名。由于该证书的根不在微软的信任列表里所以默认情况下Windows会严重警告。你需要引导用户将你的自签名根证书安装到其电脑的“受信任的根证书颁发机构”存储区。优点完全免费完全可控证书有效期、密钥长度自己定。在用户安装根证书后其效果与商业证书几乎无异在该电脑上。缺点用户体验是灾难性的。你无法要求每个用户都去执行“安装一个不明证书”这种高风险操作。这仅适用于可控的内网环境、测试场景或者给极客用户提供的一个可选步骤。对于公开发布的软件这基本不可行。对于我们寻找“完全免费”且能用于公开发布场景的目标来说类一开源免费证书是当前唯一具有实践价值的起点。接下来我们就聚焦于这一类深入探讨一个曾经流行但现在已发生重大变化的方案。3. 深入剖析从SSL.com免费证书到SignPath的变迁几年前很多教程会指向SSL.com提供的一年免费代码签名证书。这曾经是一个很好的选择但政策已经改变。SSL.com的免费证书现已不再适用于新的代码签名仅能用于SSL/TLS。这个变化本身就揭示了免费资源的不可靠性——它们可能随时关闭或改变条款。目前社区内讨论较多且相对稳定的是通过SignPath基金会获取的免费证书。SignPath本身是一个CI/CD集成签名服务平台但其旗下有一个“SignPath基金会”项目为开源软件提供免费的代码签名服务。3.1SignPath基金会证书的工作原理它并不是直接给你一个.pfx证书文件让你随意使用。其运作模式更安全、更可控项目申请你需要有一个开源项目通常托管在GitHub上并向SignPath基金会提交申请说明项目用途。审核与配置审核通过后SignPath会在其平台上为你的项目配置一个签名策略。集成签名你不能直接拿到私钥。签名动作需要在SignPath平台上完成。通常的流程是当你在GitHub上发布一个Release时通过GitHub Actions等CI/CD工具将构建好的可执行文件自动发送到SignPath的API。远程签名SignPath平台使用它们保管的、由Sectigo颁发的特定证书私钥对你的文件进行远程签名然后将已签名的文件返回或自动发布。证书链签名的证书最终链到一个名为“SignPath Foundation Code Signing CA”的中间证书而该中间证书的根证书SignPath Root CA G2并未被微软默认信任。3.2 实际操作流程与核心步骤假设你的项目是一个名为MyTool的Windows开源工具使用GitHub托管。步骤1申请与准备访问SignPath基金会网站用GitHub账号登录。创建一个新的“项目”填写项目信息、仓库链接、许可证等。提交申请并等待人工审核可能需要几天时间。审核通过后在SignPath后台你会获得一个API Token和一个Project Slug项目标识符。步骤2配置GitHub Actions自动化签名在你的仓库中创建.github/workflows/sign.yml文件。工作流的关键步骤包括在Release创建时触发。构建你的项目生成MyTool.exe。使用SignPath提供的官方Actionsignpath/signpath-action或直接调用其REST API。将API Token、Project Slug以及要签名的文件路径作为机密Secrets和输入传入。Action会将文件上传至SignPath等待签名完成然后下载已签名的文件。将已签名的文件附加到当前的GitHub Release中。一个极简的sign.yml示例框架如下name: Sign Application on: release: types: [published] jobs: sign: runs-on: windows-latest steps: - name: Checkout code uses: actions/checkoutv3 - name: Build Project run: | # 这里填入你实际的构建命令例如 # msbuild MyTool.sln /p:ConfigurationRelease # 假设最终生成 MyTool/bin/Release/MyTool.exe - name: Sign with SignPath uses: signpath/signpath-actionv1 with: api-token: ${{ secrets.SIGNPATH_API_TOKEN }} project-slug: your-project-slug signing-policy-slug: your-signing-policy-slug input-path: MyTool/bin/Release/MyTool.exe output-path: MyTool/bin/Release/MyTool-Signed.exe - name: Upload Signed Artifact uses: actions/upload-release-assetv1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} asset_path: MyTool/bin/Release/MyTool-Signed.exe asset_name: MyTool-Signed.exe asset_content_type: application/octet-stream步骤3用户端的信任问题用户下载了你发布的MyTool-Signed.exe。双击运行时可能仍会看到“Windows已保护你的电脑”但发布者可能显示为“SignPath Foundation ...”之类的信息而不是完全的“未知发布者”。要消除警告用户需要手动下载并安装SignPath的根证书。SignPath官网会提供这个证书文件.crt。用户安装后所有由SignPath基金会签名的软件在该电脑上都会被信任。3.3 优势与局限性分析优势真正的免费无需支付任何费用。支持开源流程设计围绕开源项目自动化契合开发者工作流。私钥安全私钥由SignPath专业托管避免了开发者本地私钥泄露的风险。合法性使用由正规CASectigo颁发的证书只是信任链需要额外处理。局限性这才是关键信任链不默认最大的障碍。要求最终用户手动安装根证书这在实际推广中几乎不可能实现。这将它限制在了一个“愿意折腾的开发者或早期尝鲜用户”的小圈子里。流程复杂需要配置CI/CD对不熟悉自动化流程的开发者有门槛。审核制并非申请即得需要项目符合开源要求并等待审核。服务依赖性完全依赖SignPath平台的服务持续性。注意SignPath的方案代表了当前免费代码签名的一个现实——没有完美的解决方案。它提供了标准的签名流程和相对更好的发布者标识但无法解决Windows系统默认不信任的根本问题。它适合那些用户群体本身就是技术爱好者、并且项目有明确开源属性的场景。4. 替代方案探索Certum的免费个人证书与Azure Key Vault的变通思路除了SignPath我们还可以关注其他一些边缘但可能有用的方案。4.1Certum的免费个人证书波兰的CACertum曾提供一款名为“Free Personal Signing Certificate”的产品。这款证书的初衷是用于签名电子邮件和文档但因其具有代码签名扩展属性也被一些人用于软件签名。申请流程需要下载Certum的专用客户端软件在软件内生成密钥对并提交申请。验证方式通常是向申请邮箱发送验证邮件。信任状态Certum的根证书Certum Trusted Network CA在较新版本的Windows如Win10/11中是默认受信任的。这是一个巨大优势。核心限制然而微软的代码签名策略非常严格。对于代码签名证书它不仅验证证书链是否可信还会验证证书中的“增强型密钥用法”和“证书策略”等字段。Certum的这款免费证书的证书策略标识符Certificate Policies可能表明它是“个人”用途而非“商业代码签名”用途。因此即使证书链受信signtool在签名时可能会报错如“SignerSign() failed.”错误0x80070057或者系统在验证时仍可能不将其视为有效的代码签名证书。实测中用它成功签出能被系统默认信任的.exe文件非常困难且不稳定。结论不推荐作为主要方案。可以尝试但要做好失败的心理准备且不要对其兼容性抱有过高期望。4.2 利用Azure Key Vault的代码签名证书非完全免费这是一个需要少量花费但成本极低的“准免费”方案思路很巧妙。原理Azure Key Vault是微软云上的密钥管理服务。你可以从DigiCert或GlobalSign等CA直接购买代码签名证书但私钥不下载到本地而是直接生成并存储在Azure Key Vault的HSM硬件安全模块中。然后你可以使用Azure Pipelines或本地工具通过Key Vault的API对代码进行远程签名。成本Azure Key Vault本身有很低的基础费用约几美元/月加上证书费用通常比直接购买便宜因为私钥托管在HSM证书更便宜。一年总成本可能控制在50-100美元左右远低于标准商业证书。优点证书是100%正规、被所有Windows默认信任的商业证书。私钥安全性极高HSM保护。签名可以集成到Azure DevOps的CI/CD中。缺点不是完全免费需要绑定信用卡且涉及Azure云服务有一定配置复杂度。定位适合微小企业、初创团队或严肃的个人项目愿意用极低的成本换取完全合规的代码签名。对于追求“绝对零成本”的开发者来说这算是一个“加钱上省心”的选项。5. 实操指南使用SignPath基金会证书签名的全流程演示让我们以SignPath为例完成一次从申请到发布的完整实操。这里会补充大量教程中容易忽略的细节。5.1 前期准备与申请项目要求确保你的GitHub仓库是公开的拥有明确的LICENSE文件如MIT,GPL并且有实质性的代码和发布历史。一个空仓库或刚创建的项目很难通过审核。申请过程访问https://signpath.io/并点击“Get Free Code Signing”或找到基金会页面。使用GitHub OAuth授权登录。在控制台点击“Add Project”。你需要填写Project Name 你的软件名称。Repository URL 你的GitHub仓库地址。Description 清晰描述软件用途。License 选择对应的开源许可证。提交后状态会变为“Pending Approval”。通常需要几个工作日。期间保持邮箱畅通。5.2 配置GitHub Secrets与签名策略获取凭证审核通过后在SignPath项目页面你会找到API Token 用于调用API的令牌。Project Slug 类似your-username/your-project-name。Signing Policy Slug 通常是“code-signing-windows”或类似名称。在GitHub仓库设置Secrets进入你的GitHub仓库 -Settings-Secrets and variables-Actions。点击New repository secret。创建名为SIGNPATH_API_TOKEN的Secret值为你从SignPath复制的API Token。可选你也可以将Project Slug和Signing Policy Slug设为Secrets但更常见的做法是直接写在YAML文件里因为它们不算机密。5.3 编写GitHub Actions工作流文件以下是比基础示例更健壮、包含错误处理和清理的workflow文件name: Build, Sign and Release on: push: tags: - v* # 当推送v开头的tag时触发例如 v1.0.0 jobs: build-and-sign: runs-on: windows-latest steps: - name: Checkout code uses: actions/checkoutv3 with: fetch-depth: 0 # 获取全部历史某些版本工具需要 - name: Setup .NET (示例根据你的项目调整) uses: actions/setup-dotnetv3 with: dotnet-version: 6.0.x - name: Build Release run: | dotnet publish ./MyTool.sln -c Release -p:PublishSingleFiletrue -p:PublishTrimmedtrue --self-contained true -r win-x64 -o ./publish shell: pwsh - name: List Artifacts for Debugging run: dir .\publish -Recurse shell: pwsh - name: Sign Executable with SignPath uses: signpath/signpath-actionv1 id: sign # 赋予一个id便于后续步骤引用输出 with: api-token: ${{ secrets.SIGNPATH_API_TOKEN }} organization-id: signpath-foundation # 基金会组织的固定ID project-slug: your-github-username/your-repo-name # 替换为你的 signing-policy-slug: code-signing-windows input-path: ./publish/MyTool.exe # 确保路径正确 output-path: ./publish/MyTool-Signed.exe wait-for-completion: true # 等待签名完成 timeout: 600 # 超时时间秒 - name: Verify Signature (Optional but Recommended) run: | $sigFile ./publish/MyTool-Signed.exe if (Test-Path $sigFile) { C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64\signtool.exe verify /pa /v $sigFile if ($LASTEXITCODE -ne 0) { Write-Error 签名验证失败 exit 1 } Write-Host 签名验证成功 } else { Write-Error 签名后的文件未找到 exit 1 } shell: pwsh - name: Create GitHub Release and Upload uses: softprops/action-gh-releasev1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: files: | ./publish/MyTool-Signed.exe tag_name: ${{ github.ref_name }} # 使用触发工作流的tag名 name: Release ${{ github.ref_name }} draft: false prerelease: false5.4 关键点与避坑指南路径问题Windows和Linux的路径分隔符不同。在windows-latest运行器上使用反斜杠\或正斜杠/均可但PowerShell (pwsh) 通常更兼容/。使用dir或Get-ChildItem命令列出文件是调试路径问题最直接的方法。签名验证签名步骤后强烈建议添加一个验证步骤。这能第一时间发现签名是否真的成功避免发布未签名的文件。signtool verify /pa /v命令中的/pa使用默认验证策略/v输出详细信息。SignPathAction的organization-id对于SignPath基金会项目这个值通常是固定的signpath-foundation务必确认。网络与超时远程签名依赖网络且可能需要排队。设置合理的timeout如600秒并启用wait-for-completion: true是必要的。私钥安全这是SignPath模式的最大优点之一。你永远接触不到私钥私钥泄露的风险为0。但这也意味着如果SignPath服务不可用你的签名流程就会中断。6. 当免费方案行不通时低成本替代方案与策略调整经过上面的分析你会发现完全免费且能像商业证书一样“开箱即用”的方案在公开分发的Windows软件领域几乎不存在。这是由微软的信任模型和商业生态决定的。那么当免费方案无法满足需求时我们还有什么选择6.1 调整策略接受“未知发布者”但增强软件本身的可信度如果预算真的是0并且你的用户不是技术小白可以考虑以下组合策略虽不能消除警告但能极大降低用户的顾虑使用SignPath或Certum免费证书签名即使有警告文件属性“数字签名”一栏里会显示签名信息和哈希值这比完全没有签名要专业得多。用户可以查看签名详情确认文件来自你且未被篡改。发布校验和在下载页面同时提供文件的SHA256或SHA512校验和。用户下载后可以自行校验确保文件完整性。清晰的文档与沟通在项目主页、README和发布说明中明确解释为什么会有Windows警告并提供SignPath根证书的安装指引给愿意做的用户。坦诚的沟通能赢得理解。建立项目声誉一个活跃的GitHub仓库、清晰的文档、及时的Issue回复这些都能建立信任。用户更愿意相信一个看起来活跃、负责任的开发者。6.2 极低成本方案Azure Key Vault 廉价证书如前所述每年几十到一百美元的成本对于能产生价值的项目来说是值得的投资。这带来了完全消除SmartScreen警告随时间推移和软件使用量增加信誉建立后。显示可识别的发布者名称取决于证书类型。符合企业级安全要求私钥托管在HSM。自动化集成提升发布效率。6.3 考虑跨平台或安装包策略转向非Windows平台如果你的用户群可以使用macOS或Linux这些系统对未签名软件的宽容度通常更高。使用安装包用户对.msi或.exe安装包的警惕性有时低于单个绿色.exe。使用WiX Toolset、Inno Setup或NSIS制作专业的安装包并在安装包内提供详细的说明体验会好很多。你甚至可以给安装包本身签名同样需要证书。7. 总结与个人实践建议折腾一圈免费代码签名我的核心体会是这是一场在成本、便利性和安全性之间的艰难平衡。对于纯粹的个人学习项目、内部工具或给极客朋友用的东西SignPath基金会方案是首选。它流程正规能学习到CI/CD和签名集成的完整知识并且那个“发布者”信息在属性里看着确实舒服。你需要做的就是管理好用户的预期在文档里写好“首次运行请点击‘更多信息’-‘仍要运行’”。对于有明确用户群体、希望更广泛分发、甚至未来可能产生收益的项目我强烈建议尽早考虑Azure Key Vault这类低成本商业方案。把每年一杯咖啡的钱投资在这里换来的用户体验提升和专业形象是巨大的。时间也是成本反复折腾免费方案的不确定性和用户支持成本加起来可能早已超过那点证书费用。最后无论用哪种方案请务必做好这两件事备份你的构建和签名环境配置尤其是GitHub Actions的YAML文件。免费服务可能变更你的配置是宝贵的资产。永远不要将任何有效的代码签名证书私钥如果你有的话提交到GitHub或任何公开仓库。一旦泄露后果严重。SignPath的远程签名模式在这方面提供了很好的保护。代码签名只是软件可信交付的一环。清晰的文档、良好的代码、积极的维护才是建立长期信任的基石。希望这篇长文能帮你理清思路找到最适合你当前阶段的那个“免费”或“低成本”的签名之道。