【问题标题】:Asymmetric Key not matching Enhanced Strong Name非对称密钥与增强的强名称不匹配
【发布时间】:2017-10-04 18:14:45
【问题描述】:

所以我在网上搜索了很多答案。我已经成功创建了一个模板,用于以编程方式使用简单的强名称和证书将CLR Assemblies 部署到多个(超过 100 个)SQL Server 实例和服务器......甚至不需要使用像 VISUAL STUDIO 这样的 IDE,除了语法和检查程序集。 :)

唯一的问题似乎是我用来签名的公钥,因为 C# 编译器 csc.exe 使用 SHA-1 哈希对程序集进行签名。所以唯一的解决方法是使用Enhanced Strong Naming 或MSBuild(这里不是真正的选择)。

增强的强命名是一个非常简单的过程:

  • 创建强名称密钥 (snk) 文件:

    sn.exe -k [RSA_Length] CLR_IdentityKey.snk

  • 发布公钥并使用SHA-2对其进行哈希处理

    sn.exe -p CLR_IdentityKey.snk CLR_PubKey.snk sha256

  • 延迟使用公钥对您的程序集进行签名(csc.exe 的来源决定了您程序集的 .NetFramework 兼容性)

    csc.exe /target:library /keyfile:CLR_PubKey.snk /out:CLR_Assembly.dll "YourCSFiles.cs" "YourCSFiles2.cs" "YourCSFiles3.cs" /DelaySign+

  • 然后使用 StrongName 工具使用原始密钥对程序集进行签名。

    sn.exe -Ra CLR_Assembly.dll CLR_IdentityKey.snk

想要使用增强型强名称方法签署我的程序集的主要原因有两个:

  1. 避免在多台服务器上长时间暴露私钥。
  2. 在创建 ASYMMETRIC KEY 时提供发布散列公共 snk 的替代方法以及设置加密密码的选项。

请注意,虽然我可以同时使用pfx 和简单的 snk 文件来完成此操作,但这里的程序集是一个简单的 HTTP POST 操作,并且证书的成本是令人望而却步的,因为它在 Intranet 环境中的用途很小.

现在检查已签名的程序集,我在清单中看到以下内容:

公钥(哈希算法:sha256): 002400000c80000014010000060200...

公钥令牌是 b8ee775aa5bfbc5b

显然 sn.exe 已经成功地使用 SHA-2 方法对程序集进行了签名。

不幸的是,当我尝试在 SQL Server 中基于此签名程序集创建我的非对称密钥时,似乎公钥关联不正确。

消息 10327,第 14 级,状态 1,第 14 行

为程序集创建程序集 “CLR_Assembly”失败,因为程序集“CLR_Assembly”未被授权 PERMISSION_SET = 不安全。大会被授权时 以下情况属实:数据库所有者 (DBO) 具有 UNSAFE ASSEMBLY 权限并且数据库具有 TRUSTWORTHY 数据库属性; 或程序集使用证书或非对称密钥签名 具有相应的具有 UNSAFE ASSEMBLY 权限的登录名。

示例代码: 请注意,命名实例和默认名称在位置和安全权限方面存在差异。选择的文件夹可能没有足够的权限,因此您可能必须添加它。

Powershell:

# The version of csc.exe dictates the version of .NetFramework your assembly is created.
$csc_path="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe"
$sn_path="C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.2 Tools\sn.exe"
$CLR_path="C:\Program Files\Microsoft SQL Server\MSSQL13.TESTSQL\MSSQL\JOBS\"

$CLR_Assembly_SNK=$CLR_path + "CLR_SNK.dll"
$CLR_Assembly_DelaySign=$CLR_path + "CLR_DelaySign.dll"

$cs_BackComp="C:\Program Files\Microsoft SQL Server\MSSQL13.TESTSQL\MSSQL\JOBS\BackwardsCompatibility.cs "
$cs_MyMethods="C:\Program Files\Microsoft SQL Server\MSSQL13.TESTSQL\MSSQL\JOBS\MyMethods.cs "
$cs_Main="C:\Program Files\Microsoft SQL Server\MSSQL13.TESTSQL\MSSQL\JOBS\CLR_JSON_Program.cs"

$CLR_IdentityKey=$CLR_path + "CLR_IdentityKey.snk"
$CLR_IdentityKey1=$CLR_path + "CLR_IdentityKey1.snk"
$CLR_PubKey=$CLR_path + "CLR_PubKey.snk"

#using SNK method
& $sn_path -k 2048 $CLR_IdentityKey
& $csc_path /target:library /out:$CLR_Assembly_SNK /keyfile:$CLR_IdentityKey $cs_BackComp $cs_MyMethods $cs_Main
& $sn_path -Tp $CLR_Assembly_SNK

# using delaySign+ method version
& $sn_path -k 2048 $CLR_IdentityKey1
& $sn_path -p $CLR_IdentityKey $CLR_PubKey sha256
& $csc_path /target:library /out:$CLR_Assembly_DelaySign /keyfile:$CLR_PubKey $cs_BackComp $cs_MyMethods $cs_Main /DelaySign+
& $sn_path -Ra $CLR_Assembly_DelaySign $CLR_IdentityKey
& $sn_path -Tp $CLR_Assembly_DelaySign

T-SQL 代码:

USE MASTER
GO
CREATE ASYMMETRIC KEY CLR_SNK_KEY
FROM EXECUTABLE FILE = 'C:\Program Files\Microsoft SQL Server\MSSQL13.TESTSQL\MSSQL\JOBS\CLR_SNK.dll'
CREATE LOGIN CLR_SNK
 FROM ASYMMETRIC KEY CLR_SNK_KEY
GRANT UNSAFE ASSEMBLY TO CLR_SNK
GO
CREATE ASSEMBLY CLR_SNK_ASSEMBLY
 AUTHORIZATION [dbo] 
 FROM 'C:\Program Files\Microsoft SQL Server\MSSQL13.TESTSQL\MSSQL\JOBS\CLR_SNK.dll'
 WITH PERMISSION_SET = UNSAFE
GO
DROP LOGIN CLR_SNK
DROP ASYMMETRIC KEY CLR_SNK_KEY
DROP ASSEMBLY CLR_SNK_ASSEMBLY
GO
/*DelaySign+ Version*/
 CREATE ASYMMETRIC KEY CLR_Delay_KEY
FROM EXECUTABLE FILE = 'C:\Program Files\Microsoft SQL Server\MSSQL13.TESTSQL\MSSQL\JOBS\CLR_DelaySign.dll'
CREATE LOGIN CLR_Delay
 FROM ASYMMETRIC KEY CLR_Delay_KEY
GRANT UNSAFE ASSEMBLY TO CLR_Delay
GO
-- fails here due to the ASYMMETRIC key not matching the assembly
CREATE ASSEMBLY CLR_Delay_Assembly
 AUTHORIZATION [dbo] 
 FROM 'C:\Program Files\Microsoft SQL Server\MSSQL13.TESTSQL\MSSQL\JOBS\CLR_DelaySign.dll'
 WITH PERMISSION_SET = UNSAFE

我的 C# 程序集使用 var postRequest = (HttpWebRequest)WebRequest.Create(uri);,这不是一种安全的方法,至少需要 EXTERNAL_ACCESS。

但是,SQL Server 2017 将放弃对 CAS 安全方法的支持,并引入了快速修复 sp_configure 'clr strict security` 设置。使用 UNSAFE 创建未来的 CLR。 Microsoft (April 19, 2017): CLR String Security

为什么 SQL Server 无法找到正确的公钥,而它们应该是相同的?

有人知道在 SQL Server 中获取延迟程序集的工作示例吗?

【问题讨论】:

  • 请注意,ALTER DATABASE [DB_Name] SET TRUSTWORTHY ON 是管理程序集的一种糟糕且可能是懒惰的方法。
  • 所以你完成了程序集的所有签名。但是您是否告诉 SQL Server 您信任任何用于 UNSAFE 程序集的关键材料?也就是说,您是否创建了基于密钥或证书的登录名/用户并授予它不安全的组装权限?如果是这样,您能否也发布该代码(请从您的实际密钥材料中编辑)。
  • @BenThul 添加了示例代码

标签: sql-server .net-assembly sqlclr encryption-asymmetric strongname


【解决方案1】:

为什么 SQL Server 无法找到正确的公钥,而它们应该是相同的?

如果您暂时将数据库设置为 TRUSTWORTHY ON 以便加载程序集,那么您应该能够看到问题。

SELECT * FROM sys.asymmetric_keys;
SELECT * FROM sys.assemblies;

运行之后,您应该会看到sys.asymmetric_keys 的“thumbprint”列与sys.assemblies 的“clr_name”列中显示的“publickeytoken”属性不匹配。这很可能是由于在运行 sn -p 时使用了 SHA-256,但您别无选择,因为 SHA-1 不适用于增强型强命名。非对称密钥的“指纹”是 SHA-1,您无法控制它,因此无法使它们匹配。

有人知道在 SQL Server 中获取延迟程序集的工作示例吗?

幸运的是,Enhanced Strong Naming 的文档提到使用AssemblySignatureKeyAttribute 属性来允许一些遗留场景工作,这当然可能是其中之一。事实上,使用该属性确实可以让增强型强命名发挥作用。

使用 SQLCLR 获得增强的强命名的步骤(在 SQL Server 2016 SP1 上测试):

  1. 创建身份和签名密钥对:

    sn -k 2048 IdentityKey.snk
    sn -k 2048 SignatureKey.snk
    
  2. 从两个密钥对中提取公钥:

    sn -p IdentityKey.snk IdentityPubKey.snk
    sn -p SignatureKey.snk SignaturePubKey.snk sha256
    

    请注意,身份密钥不是使用sha256,因此使用默认的sha1,而签名密钥是使用sha256。

  3. 生成AssemblySignatureKey 属性所需的publicKey 和counterSignature 值:

    sn -a IdentityPubKey.snk IdentityKey.snk SignaturePubKey.snk
    
  4. 将上一步生成的两个值复制到一个源文件中(即通常为AssemblyInfo.cs):

    [assembly:System.Reflection.AssemblySignatureKey(
    "public" +
    "key" +
    "value",
    "counter" +
    "Signature" +
    "value"
    )]
    
  5. 使用延迟签名编译程序集:

    csc /target:library /out:MyAssembly.dll SqlStoredProcedure.cs
          /keyfile:IdentityPubKey.snk /delaySign+
    
  6. 重新签署大会:

    sn -Ra MyAssembly.dll SignatureKey.snk
    
  7. 在 SQL Server 中,通过 DLL 在master 中创建非对称密钥:

    USE [master];
    
    CREATE ASYMMETRIC KEY [MyAsymKey]
    FROM EXECUTABLE FILE = N'C:\path\to\MyAssembly.dll';
    
  8. 从该非对称密钥创建登录并授予它EXTERNAL ACCESS ASSEMBLY 或UNSAFE ASSEMBLY:

    CREATE LOGIN [MyAsymKeyLogin]
    FROM ASYMMETRIC KEY [MyAsymKey];
    
    GRANT UNSAFE ASSEMBLY TO [MyAsymKeyLogin];
    

    您只需要授予其中一个,因为UNSAFE 意味着EXTERNAL ACCESS,但从 SQL Server 2017 开始,如果您使用启用了clr strict 的默认配置,那么这需要是UNSAFE ASSEMBLY。

  9. 更改目标数据库并创建程序集:

    USE [Test];
    ALTER DATABASE CURRENT SET TRUSTWORTHY OFF; -- Just to be sure!
    
    CREATE ASSEMBLY [MyAssembly]
    FROM N'C:\path\to\MyAssembly.dll'
    WITH PERMISSION_SET = UNSAFE;
    

附:您的其他顾虑大多不是问题:

  1. 不确定您认为私钥是如何被公开的,但它不是ASYMMETRIC KEY 的一部分(因为它是从程序集创建的),因此没有这种可能性。
  2. 无法通过CREATE ASYMMETRIC KEY 设置密码,因为私钥不存在(因为它是从程序集创建的)。
  3. 如果您更喜欢使用证书,则无需支付任何费用,因为自签名证书(通过MAKECERT 或 PowerShell)很好,尤其是对于这是一个小型内部项目。使用证书的一个好处是您可以从十六进制字节而不是文件或程序集创建它,并且由于您还可以从十六进制字节创建程序集,因此您的安装脚本可以完全移植,因为它没有任何文件系统参考:-)。

【讨论】:

  • +1 用于回答一个尘土飞扬的问题,并用旧的答案加倍努力。虽然我改变了我的思维过程(这必须在不同的版本上工作,所以 SQL Server 2008 R2 到 2017),我很欣赏详细、清晰的答案。
猜你喜欢
  • 2016-07-31
  • 2010-10-30
  • 1970-01-01
  • 2011-09-29
  • 1970-01-01
  • 2011-01-14
  • 2011-08-17
  • 2015-12-30
  • 2014-07-08
相关资源
最近更新 更多