非对称密钥不匹配增强的强名称

Asymmetric Key not matching Enhanced Strong Name

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

唯一的问题似乎是我用来签名的 public 密钥,因为 C# 编译器 csc.exe 使用 SHA-1 散列来签署程序集。所以唯一的解决方法是使用 Enhanced Strong NamingMSBuild(这里不是真正的选项)。

增强型强命名是一个足够简单的过程:

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

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

请注意,虽然我可以同时使用 pfx 和一个简单的 snk 文件来完成此操作,但此处的程序集是一个简单的 HTTP POST 操作,并且证书的成本高得令人望而却步在内网环境中很少使用。

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

Public key (hash algorithm: sha256): 002400000c80000014010000060200...

Public key token is b8ee775aa5bfbc5b

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

不幸的是,当我尝试基于 SQL 服务器中的这个签名程序集创建我的非对称密钥时,似乎 public 密钥关联不正确。

Msg 10327, Level 14, State 1, Line 14

CREATE ASSEMBLY for assembly 'CLR_Assembly' failed because assembly 'CLR_Assembly' is not authorized for PERMISSION_SET = UNSAFE. The assembly is authorized when either of the following is true: the database owner (DBO) has UNSAFE ASSEMBLY permission and the database has the TRUSTWORTHY database property on; or the assembly is signed with a certificate or an asymmetric key that has a corresponding login with UNSAFE ASSEMBLY permission.

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

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 服务器找不到正确的 public 密钥,而它们应该是相同的?

有谁知道在 SQL 服务器中获取延迟程序集的工作示例?

Why is SQL Server unable to find the correct public key when they are supposedly one and the same?

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

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

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

Does anyone know of a working example of getting delayed assemblies in SQL Server?

幸运的是,Enhanced Strong Naming mentions using the AssemblySignatureKeyAttribute 属性的文档允许一些遗留场景工作,这当然是一个。事实上,使用该属性确实允许增强的强命名工作。

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

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

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

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

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

  3. 生成 AssemblySignatureKey 属性所需的 publicKeycounterSignature 值:

    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 服务器中,通过 DLL 在 master 中创建非对称密钥:

    USE [master];
    
    CREATE ASYMMETRIC KEY [MyAsymKey]
    FROM EXECUTABLE FILE = N'C:\path\to\MyAssembly.dll';
    
  8. 从该非对称密钥创建登录并授予它 EXTERNAL ACCESS ASSEMBLYUNSAFE 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;
    

P.S。您的其他顾虑大多不是问题:

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