为 .NET 项目添加强签名(Strong Name Signing)

2 阅读4分钟

为 .NET 项目添加强签名(Strong Name Signing)

什么是强签名?

强签名(Strong Name Signing)是 .NET Framework 提供的一种Assembly标识机制,它会为您的程序集创建一个唯一的加密公钥/私钥对,并将公钥信息嵌入到程序集的元数据中。

强签名后的程序集会具有:

  • 唯一性:公钥 token 可以唯一标识发布者
  • 完整性:包含数字签名,可以验证程序集未被篡改
  • 版本控制:支持程序集的精确版本绑定
  • GAC支持:可以安装到全局程序集缓存(GAC)中

为什么需要添加强签名?

当您将 NuGet 包发布到 NuGet.org 或私有 NuGet 服务器时,如果包中包含强签名的依赖项,您也需要对您的包进行强签名,否则:

  • 可能导致程序集绑定失败
  • 在某些场景下无法正确引用
  • 可能影响某些高级 .NET 特性的使用

操作步骤

步骤 1:生成强名称密钥文件(.snk)

在项目目录下使用 PowerShell 生成无密码保护的 SNK 文件:

$snkPath = "c:\YourPath\IT.Tangdao.Core\IT.Tangdao.Core\IT.Tangdao.Core.snk"
$rsa = New-Object System.Security.Cryptography.RSACryptoServiceProvider(2048)
$snkBytes = $rsa.ExportCspBlob($true)
[System.IO.File]::WriteAllBytes($snkPath, $snkBytes)
Write-Host "SNK 文件已生成: $snkPath"

说明

  • RSACryptoServiceProvider(2048) 表示使用 2048 位的 RSA 加密算法,这是当前推荐的安全强度
  • $true 参数表示包含私钥(用于签名)
  • SNK 文件会保存在项目目录下

$rsa.ExportCspBlob($true) 导出的是 CSP Blob 格式,而 Visual Studio 期望的是 .snk 文件标准格式

两种格式的区别:

格式生成方式VS能否识别
CSP BlobExportCspBlob(true)❌ 可能不兼容
SNK 标准格式sn -k 命令✅ 完全兼容

如果出现不兼容,使用以下方案:

方案1:使用纯 PowerShell 生成标准 SNK(推荐)

powershell

$snkPath = "c:\YourPath\IT.Tangdao.Core\IT.Tangdao.Core\IT.Tangdao.Core.snk"

# 创建目录(如果不存在)
$directory = Split-Path $snkPath -Parent
if (-not (Test-Path $directory)) {
    New-Item -ItemType Directory -Path $directory -Force
}

# 使用 .NET 的正确方式生成 SNK
$cspParams = New-Object System.Security.Cryptography.CspParameters
$cspParams.KeyNumber = 1  # 签名密钥
$rsa = New-Object System.Security.Cryptography.RSACryptoServiceProvider(2048, $cspParams)

# 导出私钥(包含公钥)
$privateKey = $rsa.ExportCspBlob($true)

# 写入文件
[System.IO.File]::WriteAllBytes($snkPath, $privateKey)

Write-Host "SNK 文件已生成: $snkPath"

方案2:直接调用 sn.exe(最稳妥)

powershell

$snkPath = "c:\YourPath\IT.Tangdao.Core\IT.Tangdao.Core\IT.Tangdao.Core.snk"

# 创建目录
$directory = Split-Path $snkPath -Parent
if (-not (Test-Path $directory)) {
    New-Item -ItemType Directory -Path $directory -Force
}

# 调用 Visual Studio 的 sn.exe
& "C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\sn.exe" -k $snkPath

Write-Host "SNK 文件已生成: $snkPath"

方案3:最简单的一行命令

powershell

# 使用 sn.exe(需要 Visual Studio Build Tools)
sn -k "c:\YourPath\IT.Tangdao.Core\IT.Tangdao.Core\IT.Tangdao.Core.snk"

步骤 2:配置项目文件(.csproj)

打开 IT.Tangdao.Core.csproj 文件,在 <PropertyGroup> 节点中添加以下两个配置项:

<PropertyGroup>
    <!-- 其他现有配置项... -->
    
    <!-- 启用程序集签名 -->
    <SignAssembly>true</SignAssembly>
    
    <!-- 指定强名称密钥文件路径 -->
    <AssemblyOriginatorKeyFile>IT.Tangdao.Core.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>

配置说明

  • SignAssembly:设置为 true 表示启用程序集签名
  • AssemblyOriginatorKeyFile:指定 SNK 密钥文件的相对路径(相对于项目文件)

步骤 3:验证构建

在命令行中执行构建命令:

dotnet build

如果构建成功且没有错误,说明强签名配置已生效。

步骤 4:验证程序集是否已签名(可选)

您可以使用反编译工具(如 ILSpy、dnSpy)或 .NET 工具来验证程序集是否已正确签名:

# 使用 .NET SDK 自带工具查看程序集信息
dotnet list package

或查看生成的 DLL 文件属性,确认是否有公钥标记。

重要注意事项

1. SNK 文件管理

  • 妥善保管:SNK 文件包含私钥信息,请妥善保管
  • 不要提交到 Git:建议将 SNK 文件添加到 .gitignore
  • 备份:在安全的地方备份您的 SNK 文件

2. 版本兼容性

  • 一旦为程序集生成了强名称并发布,更换密钥会导致签名不匹配
  • 如果您的包已被其他项目引用,更换密钥会影响这些项目
  • 建议在项目初期就确定是否需要强签名

3. 有密码保护 vs 无密码保护

无密码保护(本次使用)

  • 优点:构建过程简单,适合 CI/CD
  • 缺点:如果文件泄露,他人可使用您的身份签名

有密码保护

  • 优点:更安全,需要密码才能使用私钥
  • 缺点:每次构建需要输入密码,不适合自动化构建
  • 生成方法:使用 sn -k 或 Visual Studio 的签名功能

4. 对已有项目的影响

  • 如果项目已经被其他项目引用,更改签名可能需要重新构建引用项目
  • 建议在包的 major 版本升级时考虑签名策略的变化

常见问题

Q1:构建失败,提示 "Cannot import the following key file"?

原因:SNK 文件路径不正确或文件不存在。

解决方法

  • 确认 AssemblyOriginatorKeyFile 的路径是否正确
  • 确认 SNK 文件确实存在于指定位置
  • 使用相对路径时,确保路径相对于项目文件(.csproj)所在目录

Q2:已经发布的 NuGet 包可以重新签名吗?

答案:不可以。已发布的 NuGet 包内容不可更改。

建议

  • 修复后发布新版本
  • 在发布前确保配置正确

Q3:SNK 文件可以转换为 pfx 文件吗?

答案:可以,但通常不必要。

说明

  • SNK 用于强名称签名(Strong Name)
  • PFX(Personal Information Exchange)用于 Authenticode 签名(代码签名)
  • 这是两种不同的签名系统

Q4:如何排除 SNK 文件不打包到 NuGet 包中?

默认情况下,SNK 文件不会被包含在 NuGet 包中。如果您需要显式排除:

<ItemGroup>
    <None Include="IT.Tangdao.Core.snk" />
</ItemGroup>

总结

为您的 .NET 项目添加强签名是一个相对简单的过程,主要包括:

  1. ✅ 生成 SNK 密钥文件
  2. ✅ 在 csproj 中配置签名选项
  3. ✅ 验证构建成功

完成这些步骤后,您的程序集将具有强名称,可以顺利发布到 NuGet 并被其他项目引用。


生成日期:2026-05-10

适用框架:.NET Core / .NET Framework

参考链接