Electron代码签名:Windows、macOS应用签名指南
为什么代码签名如此重要?
在当今的数字时代,用户安全是首要考虑因素。当你分发Electron应用时,如果没有正确的代码签名,用户会遇到各种安全警告和障碍:
- macOS Gatekeeper警告:"无法打开应用,因为无法验证开发者"
- Windows SmartScreen过滤:"Windows已保护你的电脑"
- 安装被阻止:用户需要手动绕过安全设置
代码签名(Codesigning)是一种安全技术,用于证明应用程序是由可信开发者创建的。它不仅是技术需求,更是建立用户信任的关键。
macOS代码签名完整指南
准备工作
在开始签名macOS应用前,你需要:
- 加入Apple开发者计划(年费99美元)
- 安装Xcode(必须在macOS系统上)
- 获取签名证书:
- 登录Apple开发者门户
- 创建App ID
- 生成开发和生产证书
签名证书类型
| 证书类型 | 用途 | 有效期 |
|---|---|---|
| Developer ID Application | 分发到App Store之外 | 1年 |
| Developer ID Installer | 签名安装包 | 1年 |
| Mac App Distribution | App Store分发 | 1年 |
使用Electron Forge进行签名
Electron Forge是官方推荐的构建工具,集成了完整的签名流程:
// forge.config.js
module.exports = {
packagerConfig: {
osxSign: {
identity: "Developer ID Application: Your Name (TEAMID)",
"hardened-runtime": true,
entitlements: "entitlements.plist",
"entitlements-inherit": "entitlements.plist",
"signature-flags": "library"
},
osxNotarize: {
appleId: process.env.APPLE_ID,
appleIdPassword: process.env.APPLE_ID_PASSWORD,
teamId: process.env.APPLE_TEAM_ID
}
},
makers: [
{
name: '@electron-forge/maker-dmg',
config: {
background: './assets/dmg-background.png',
format: 'ULFO'
}
}
]
};
公证(Notarization)流程
macOS要求所有应用都要经过Apple的公证过程:
手动签名流程
如果你需要更精细的控制,可以使用@electron/osx-sign直接签名:
const { sign } = require('@electron/osx-sign');
sign({
app: '/path/to/MyApp.app',
identity: 'Developer ID Application: Your Name (TEAMID)',
'hardened-runtime': true,
entitlements: './entitlements.plist',
'entitlements-inherit': './entitlements.plist'
}).then(() => {
console.log('签名成功');
}).catch((err) => {
console.error('签名失败:', err);
});
Windows代码签名深度解析
证书选择策略
Windows代码签名经历了重大变革,自2023年6月起,Microsoft要求使用EV代码签名证书:
| 证书类型 | 特点 | 适用场景 | 成本 |
|---|---|---|---|
| EV代码签名证书 | 硬件存储,最高信任级别 | 正式发布,消除SmartScreen警告 | $$$ |
| Azure可信签名 | 云签名,Microsoft官方方案 | 新项目,成本较低 | $$ |
| 传统代码签名 | 已淘汰,不再有效 | 不推荐使用 | $ |
EV证书工作流程
使用Electron Forge进行Windows签名
// forge.config.js - Windows配置
module.exports = {
packagerConfig: {
windowsSign: {
signWithParams: '/a /fd sha256 /tr http://timestamp.digicert.com /td sha256',
signToolPath: 'C:/Program Files (x86)/Windows Kits/10/bin/10.0.19041.0/x64/signtool.exe',
certificateFile: process.env.WINDOWS_CERT_PATH,
certificatePassword: process.env.WINDOWS_CERT_PASSWORD
}
},
makers: [
{
name: '@electron-forge/maker-squirrel',
config: {
certificateFile: process.env.WINDOWS_CERT_PATH,
certificatePassword: process.env.WINDOWS_CERT_PASSWORD,
signWithParams: '/a /fd sha256 /tr http://timestamp.digicert.com /td sha256'
}
}
]
};
Azure可信签名方案
Azure可信签名是Microsoft的新一代签名方案,无需硬件令牌:
// 使用Azure可信签名的配置
const { sign } = require('@electron/windows-sign');
await sign({
app: 'path/to/app.exe',
azureSigning: {
clientId: process.env.AZURE_CLIENT_ID,
clientSecret: process.env.AZURE_CLIENT_SECRET,
tenantId: process.env.AZURE_TENANT_ID,
certificateName: 'my-signing-cert'
},
timestampServer: 'http://timestamp.digicert.com'
});
跨平台签名最佳实践
环境变量管理
安全地管理签名凭证:
# .env.example 文件
APPLE_ID=your_apple_id@example.com
APPLE_ID_PASSWORD=app-specific-password
APPLE_TEAM_ID=TEAM123456
WINDOWS_CERT_PATH=./certs/example.pfx
WINDOWS_CERT_PASSWORD=secure_password
AZURE_CLIENT_ID=azure_client_id
AZURE_CLIENT_SECRET=azure_client_secret
AZURE_TENANT_ID=azure_tenant_id
CI/CD集成示例
GitHub Actions工作流配置:
name: Build and Sign
on: [push, pull_request]
jobs:
build-and-sign:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build application
run: npm run make
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
WINDOWS_CERT: ${{ secrets.WINDOWS_CERT }}
WINDOWS_CERT_PASSWORD: ${{ secrets.WINDOWS_CERT_PASSWORD }}
- name: Notarize macOS app
if: matrix.os == 'macos-latest'
run: |
npx @electron/notarize-cli notarize \
--file "out/MyApp-darwin-x64/MyApp.app" \
--bundle-id "com.example.myapp" \
--apple-id $APPLE_ID \
--password $APPLE_ID_PASSWORD \
--team-id $APPLE_TEAM_ID
常见问题排查表
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| macOS公证失败 | 证书问题或网络连接 | 检查证书有效性,重试 |
| Windows签名无效 | 时间戳服务器问题 | 更换时间戳服务器 |
| SmartScreen警告 | EV证书未正确应用 | 确保证书为EV类型 |
| 应用无法启动 | 权限配置错误 | 检查entitlements文件 |
安全增强措施
权限配置文件(Entitlements)
创建entitlements.plist文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.device.audio-input</key>
<true/>
<key>com.apple.security.device.camera</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
</dict>
</plist>
时间戳服务选择
确保签名长期有效:
| 时间戳服务 | 提供商 | 可靠性 |
|---|---|---|
| http://timestamp.digicert.com | DigiCert | ⭐⭐⭐⭐⭐ |
| http://timestamp.sectigo.com | Sectigo | ⭐⭐⭐⭐ |
| http://timestamp.globalsign.com | GlobalSign | ⭐⭐⭐⭐ |
总结与建议
代码签名不再是可选项,而是Electron应用分发的必需品。通过本指南,你应该能够:
- 理解不同平台的签名要求:macOS需要公证,Windows需要EV证书
- 选择合适的工具链:Electron Forge提供最完整的解决方案
- 实现自动化签名流程:通过CI/CD确保每次构建都正确签名
- 处理常见问题:掌握排查签名问题的技巧
记住,代码签名不仅是技术实现,更是建立用户信任的基础。投资正确的签名策略,将为你的Electron应用带来更好的用户体验和市场接受度。
下一步行动建议:
- 评估项目需求,选择合适的证书类型
- 设置自动化构建和签名流水线
- 定期更新证书和检查签名状态
- 监控各平台签名政策变化
通过遵循本指南的最佳实践,你将能够为用户提供安全、可信的Electron应用程序,避免安全警告,提升用户体验。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



