sql-server - 非对称 key 与增强型强名称不匹配

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

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

唯一的问题似乎是我用来签名的公钥,因为 C# 编译器 csc.exe 使用 SHA-1 哈希来签署程序集。因此,唯一的解决方法是使用增强型强命名MSBuild(这里实际上不是一个选项)。

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

  • 创建强名称 key (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 工具使用原始 key 对程序集进行签名。

    sn.exe -Ra CLR_Assembly.dll CLR_IdentityKey.snk

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

  1. 避免在多台服务器上暴露私钥一段时间。
  2. 提供发布散列公共(public) snk 的替代方案,并可选择在创建异步 key 时设置加密密码。

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

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

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

Public key token is b8ee775aa5bfbc5b

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

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

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 创建 future 的 CLR。 Microsoft (April 19, 2017): CLR String Security

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

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

最佳答案

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 的“指纹”列与 sys.assemblies 的“clr_name”列中显示的“publickeytoken”属性不匹配。这很可能是由于运行时使用 SHA-256 sn -p ,但您别无选择,因为 SHA-1 不适用于增强型强命名。非对称 key 的“指纹”是 SHA-1,您无法控制它,因此无法使它们匹配。

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

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

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

  1. 创建身份和签名 key 对:

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

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

    请注意,身份 key 使用 sha256 ,因此使用默认值 sha1 ,而签名 key 使用 sha256 .

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

    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 中,在 master 中创建非对称 key 来自 DLL:

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

附注您的其他担忧大多不是问题:

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

关于sql-server - 非对称 key 与增强型强名称不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43818917/

相关文章:

sql-server - 什么样的SQL-Server锁级别适合insert?

python - 使用 sqlalchemy 和 pyodbc 在 MS SQL Server 上获取查询的返回行

sql - SQL中如何将外键设为NULLABLE?

c# - C# 中 "internal"关键字的实际用途

c# - 用户取消查询时如何回滚SQL CLR存储过程?

c# - 如何读取 FOR XML SQL Server 查询的完整结果?

asp.net-mvc - 为什么 ASP.NET MVC 4 有这么多 NuGet 包,哪些真正重要?

c# - 将程序集加载到 applicationBase C# 之外的 AppDomain

c# - 如何在 CLR 函数中获取 SQL 字符串的排序规则?

.net - Sql Server 中的 CLR 集成可能出现哪些问题