代码签名 #

一、签名概述 #

1.1 为什么需要签名 #

原因 说明
安全验证 确保应用来源可信
防止篡改 检测应用是否被修改
系统信任 避免安全警告
应用商店 上架必要条件

1.2 各平台签名要求 #

平台 签名类型 说明
Windows Authenticode 需要代码签名证书
macOS Developer ID 需要 Apple 开发者账号
Linux GPG 可选,用于验证

二、Windows 签名 #

2.1 获取证书 #

text
证书类型:
- EV 代码签名证书:最高信任级别
- OV 代码签名证书:标准信任级别

证书颁发机构:
- DigiCert
- Sectigo
- GlobalSign

2.2 配置签名 #

json
// tauri.conf.json
{
    "bundle": {
        "windows": {
            "certificateThumbprint": "your-certificate-thumbprint",
            "digestAlgorithm": "sha256",
            "timestampUrl": "http://timestamp.digicert.com",
            "signCommand": {
                "cmd": "signtool",
                "args": [
                    "sign",
                    "/fd", "sha256",
                    "/sha1", "your-certificate-thumbprint",
                    "/t", "http://timestamp.digicert.com",
                    "/v"
                ]
            }
        }
    }
}

2.3 使用 SignTool #

bash
# 基本签名
signtool sign /fd sha256 /sha1 YOUR_THUMBPRINT /t http://timestamp.digicert.com app.exe

# 使用证书文件
signtool sign /fd sha256 /f certificate.pfx /p password /t http://timestamp.digicert.com app.exe

2.4 环境变量签名 #

bash
# 设置环境变量
export TAURI_SIGNING_PRIVATE_KEY="your-private-key"
export TAURI_SIGNING_PRIVATE_KEY_PASSWORD="your-password"

# 构建
pnpm tauri build

2.5 Azure Key Vault #

json
{
    "windows": {
        "signCommand": {
            "cmd": "azuresigntool",
            "args": [
                "sign",
                "--azure-key-vault-url", "https://your-vault.vault.azure.net",
                "--azure-key-vault-client-id", "your-client-id",
                "--azure-key-vault-client-secret", "your-client-secret",
                "--azure-key-vault-certificate", "your-certificate-name",
                "--timestamp-url", "http://timestamp.digicert.com",
                "--file-digest", "sha256"
            ]
        }
    }
}

三、macOS 签名 #

3.1 准备工作 #

text
1. 注册 Apple Developer Program
2. 获取 Developer ID Application 证书
3. 安装 Xcode
4. 配置开发者账号

3.2 配置签名 #

json
// tauri.conf.json
{
    "bundle": {
        "macOS": {
            "signingIdentity": "Developer ID Application: Your Name (TEAM_ID)",
            "providerShortName": "TEAM_ID",
            "hardenedRuntime": true,
            "entitlements": "entitlements.plist"
        }
    }
}

3.3 Entitlements 配置 #

xml
<!-- 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.network.client</key>
    <true/>
    <key>com.apple.security.files.user-selected.read-write</key>
    <true/>
</dict>
</plist>

3.4 公证 #

bash
# 构建应用
pnpm tauri build

# 创建 ZIP
ditto -c -k --keepParent "src-tauri/target/release/bundle/macos/MyApp.app" "MyApp.zip"

# 提交公证
xcrun notarytool submit "MyApp.zip" \
    --apple-id "your@email.com" \
    --team-id "TEAM_ID" \
    --password "app-specific-password" \
    --wait

# Staple 公证结果
xcrun stapler staple "src-tauri/target/release/bundle/macos/MyApp.app"

3.5 自动化公证 #

yaml
# .github/workflows/release.yml
name: Release macOS

on: [release]

jobs:
    build:
        runs-on: macos-latest
        steps:
            - uses: actions/checkout@v3
            
            - name: Build
              run: pnpm tauri build
            
            - name: Notarize
              env:
                  APPLE_ID: ${{ secrets.APPLE_ID }}
                  APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
                  APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
              run: |
                  ditto -c -k --keepParent "src-tauri/target/release/bundle/macos/MyApp.app" "MyApp.zip"
                  xcrun notarytool submit "MyApp.zip" --apple-id "$APPLE_ID" --team-id "$APPLE_TEAM_ID" --password "$APPLE_PASSWORD" --wait
                  xcrun stapler staple "src-tauri/target/release/bundle/macos/MyApp.app"

四、Linux 签名 #

4.1 GPG 签名 #

bash
# 生成 GPG 密钥
gpg --full-generate-key

# 列出密钥
gpg --list-keys

# 导出公钥
gpg --armor --export your@email.com > public.key

4.2 签名 DEB 包 #

bash
# 构建
pnpm tauri build

# 签名
dpkg-sig -k your@email.com --sign builder src-tauri/target/release/bundle/deb/myapp_1.0.0_amd64.deb

4.3 签名 AppImage #

bash
# 使用 gpg2 签名
gpg2 --armor --detach-sign myapp.AppImage

# 验证签名
gpg2 --verify myapp.AppImage.sig myapp.AppImage

五、CI/CD 签名 #

5.1 GitHub Actions #

yaml
name: Build and Sign

on: [push]

jobs:
    build-windows:
        runs-on: windows-latest
        steps:
            - uses: actions/checkout@v3
            
            - name: Install certificate
              run: |
                  echo "${{ secrets.WINDOWS_CERTIFICATE }}" | base64 -d > certificate.pfx
                  certutil -importpfx certificate.pfx "${{ secrets.WINDOWS_CERT_PASSWORD }}"
            
            - name: Build
              env:
                  TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.WINDOWS_PRIVATE_KEY }}
                  TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.WINDOWS_KEY_PASSWORD }}
              run: pnpm tauri build

    build-macos:
        runs-on: macos-latest
        steps:
            - uses: actions/checkout@v3
            
            - name: Install certificate
              env:
                  CERTIFICATE_BASE64: ${{ secrets.MACOS_CERTIFICATE }}
                  CERTIFICATE_PASSWORD: ${{ secrets.MACOS_CERT_PASSWORD }}
              run: |
                  echo $CERTIFICATE_BASE64 | base64 -d > certificate.p12
                  security create-keychain -p actions temp.keychain
                  security import certificate.p12 -k temp.keychain -P $CERTIFICATE_PASSWORD -T /usr/bin/codesign
                  security set-key-partition-list -S apple-tool:,apple: -s -k actions temp.keychain
            
            - name: Build
              env:
                  APPLE_ID: ${{ secrets.APPLE_ID }}
                  APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
                  APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
              run: |
                  pnpm tauri build
                  # 公证步骤...

5.2 安全存储密钥 #

text
GitHub Secrets:
- WINDOWS_CERTIFICATE: Base64 编码的证书
- WINDOWS_CERT_PASSWORD: 证书密码
- MACOS_CERTIFICATE: Base64 编码的证书
- MACOS_CERT_PASSWORD: 证书密码
- APPLE_ID: Apple ID
- APPLE_PASSWORD: App 专用密码
- APPLE_TEAM_ID: 团队 ID

六、验证签名 #

6.1 Windows 验证 #

powershell
# 使用 SignTool 验证
signtool verify /pa /all app.exe

# 使用 PowerShell
Get-AuthenticodeSignature app.exe

6.2 macOS 验证 #

bash
# 验证签名
codesign --verify --deep --strict --verbose=2 MyApp.app

# 验证公证
spctl --assess --verbose --type execute MyApp.app

6.3 Linux 验证 #

bash
# 验证 GPG 签名
gpg --verify package.deb.sig package.deb

七、最佳实践 #

7.1 证书管理 #

text
1. 使用硬件令牌存储证书
2. 限制证书访问权限
3. 定期轮换证书
4. 使用 CI/CD 密钥管理

7.2 签名流程 #

text
1. 本地开发时不签名
2. CI/CD 中自动签名
3. 发布前验证签名
4. 记录签名信息

7.3 错误处理 #

bash
# Windows 签名失败
signtool sign /debug ...

# macOS 签名失败
codesign --verify --verbose=4 MyApp.app

八、总结 #

8.1 核心要点 #

要点 说明
Windows Authenticode 签名
macOS Developer ID + 公证
Linux GPG 签名(可选)
CI/CD 自动化签名流程
密钥管理 安全存储证书

8.2 下一步 #

现在你已经掌握了代码签名,接下来让我们学习 多平台构建,了解如何构建跨平台应用!

最后更新:2026-03-28