将 .Net 程序集添加到 SQL CLR,而不打开 TRUSTWORTHY

use*_*986 5 sql-server-2008 sql-server best-practices sql-clr signature

我正在尝试使用 Solomon Rutzky 在其后程序集部署中提供的指导来添加“System.Messaging.dll”,并使用非对称密钥使用 UNSAFE 或 EXTERNAL_ACCESS 权限,但我在第一个障碍上失败了。

脚本的第一部分是从程序集创建证书;

CREATE CERTIFICATE [MS.NETcer] FROM EXECUTABLE FILE = 'C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Messaging.dll';
GO
Run Code Online (Sandbox Code Playgroud)

但是,当我执行此操作时,我收到错误;

Msg 15208, Level 16, State 1, Line 1
The certificate, asymmetric key, or private key file does not exist or has invalid format.
Run Code Online (Sandbox Code Playgroud)

我用来执行命令的帐户具有“sysadmin”服务器角色。这是在 SQL Server 2008 实例上。

请问有人对为什么失败有任何想法吗?

---------- 更新 1 -----------

我采纳了所罗门的建议并修改了我的脚本,使其看起来像这样;

CREATE ASYMMETRIC KEY [Key.System.Messaging] FROM EXECUTABLE FILE = 'C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Messaging.dll';
GO

CREATE LOGIN [CLR.Login.System.Messaging] FROM ASYMMETRIC KEY [Key.System.Messaging];
GO

GRANT UNSAFE ASSEMBLY TO [CLR.Login.System.Messaging];
GO
Run Code Online (Sandbox Code Playgroud)

到目前为止一切都很好。我现在运行 CREATE ASSEMBLY 命令将程序集添加到 SQLCLR;

CREATE ASSEMBLY [System.Messaging]
FROM 'C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Messaging.dll'
WITH PERMISSION_SET = UNSAFE
GO
Run Code Online (Sandbox Code Playgroud)

但这会因错误而失败;

为程序集“System.Messaging”创建程序集失败,因为程序集“System.Windows.Forms”未获得 PERMISSION_SET = UNSAFE 的授权。当满足以下任一条件时,程序集被授权:数据库所有者 (DBO) 具有 UNSAFE ASSEMBLY 权限,并且数据库具有 TRUSTWORTHY 数据库属性;或者程序集是使用具有 UNSAFE ASSEMBLY 权限的相应登录名的证书或非对称密钥进行签名的。

我尝试为“System.Windows.Forms”创建非对称密钥

CREATE ASYMMETRIC KEY [Key.System.Windows.Forms] FROM EXECUTABLE FILE = 'C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Windows.Forms.dll';
GO
Run Code Online (Sandbox Code Playgroud)

但这失败了;

消息 15468,级别 16,状态 1,第 1 行 生成非对称密钥期间发生错误。

所以我尝试了;

CREATE CERTIFICATE [Cer.System.Windows.Forms] FROM EXECUTABLE FILE = 'C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Windows.Forms.dll';
GO
Run Code Online (Sandbox Code Playgroud)

这失败了;

消息 15208,级别 16,状态 1,第 1 行 证书、非对称密钥或私钥文件不存在或格式无效。

所以现在我再次陷入困境,想知道是否可以在 SQL CLR 中使用 System.Messaging.dll 而不必启用 TRUSTWORTHY 数据库属性(以及到底为什么 System.Messaging.dll 需要依赖于 System .Windows.Forms.dll!)

任何想法都感激不尽

Sol*_*zky 3

我在 SQL Server 2017 CU12 上执行相同的命令并得到相同的 15208 错误。然后我尝试了以下操作:

\n
CREATE ASYMMETRIC KEY [MS.NETsnk] FROM EXECUTABLE FILE =\n\'C:\\Windows\\Microsoft.NET\\Framework\\v2.0.50727\\System.Messaging.dll\';\n
Run Code Online (Sandbox Code Playgroud)\n

成功了!(名称中的“snk”代表“强名称密钥”,因为从技术上讲,这不是证书)。

\n

据我所知,大多数 CLR 2.0 的 .NET Framework 库(即 .NET Framework 版本 2.0、3.0 和 3.5)都没有使用证书签名。大多数(但不是全部)mscor*.dll文件以及只有一个System.*.dll \xe2\x80\x94 System.EnterpriseServices.Thunk.dll \xe2\x80\x94 使用证书签名。其余的仅使用强名称密钥/强名称。

\n

从 CLR 4.0(即 .NET Framework 版本 4.*)开始,似乎所有.NET Framework 库都使用证书进行签名。

\n

因此,更精确的规则是:

\n
    \n
  • 对于 CLR 4.0(即 SQL Server 版本 2012 及更高版本),使用CREATE CERTIFICATE

    \n
  • \n
  • 对于 CLR 2.0(即 SQL Server 版本 2005、2008 和 2008 R2),请使用CREATE ASYMMETRIC KEY. 但是,如果这样做会导致 15208 错误(“证书、非对称密钥或私钥文件无效或不存在;或者您没有权限”),则切换到CREATE CERTIFICATE.

    \n

    该组一开始的原因ASYMMETRIC KEY是需要使用的可能性非常CERTIFICATE低。我尝试在 SQL Server 2019(使用 CLR 4.0)和 SQL Server 2005(使用 CLR 2.0)中导入System.EnterpriseServices.Thunk.dll ,但在 SQL Server 2005 中的 \xe2\x80\x94 msg 6507 中均失败, SQL Server 2019 \xe2\x80\x94 中的 msg 6544 抱怨“格式错误的程序集”(意味着它是混合模式/非纯 MSIL 程序集)。我还尝试在 SQL Server 2005 中导入一些mscor*库,但它们失败并出现相同的 6507 错误(核心库中包含非托管代码也就不足为奇了)。CREATE CERTIFICATE因此,在导入 CLR 2.0 的 .NET Framework 库时,很可能甚至无法使用。

    \n
  • \n
\n

现在, System.Messaging似乎有几个依赖项:

\n
    \n
  • 系统.配置.安装
  • \n
  • 系统.运行时.序列化.formatters.soap
  • \n
  • 系统.windows.forms
  • \n
  • 系统图
  • \n
  • 可达性
  • \n
  • 系统目录服务
  • \n
\n

这些依赖项会自动导入,因为源CREATE ASSEMBLY是文件而不是VARBINARY文字/十六进制字节。在自动导入依赖项时,即使我们已经创建了非对称密钥并且其他依赖项已正确导入,但system.windows.forms上的操作仍会失败,并声称它未获得 授权。UNSAFE

\n

进一步调查显示,用于system.windows.forms的强名称密钥与用于其他库的强名称密钥不同。成功导入的库的公钥令牌为b03f5f7f11d50a3a,而失败的库的公钥令牌为b77a5c561934e089。正如OP发现的那样,从system.windows.forms创建非对称密钥不起作用。从库创建证书也不起作用,但这更容易解释:该库没有使用证书签名;-)。然而,创建非对称密钥的问题可能是由于system.windows.forms的签名方式 造成的。它使用 ECMA 签名,在库中放置标准占位符值而不是公钥,并且该占位符值不是有效的公钥。欲了解更多信息,请参阅以下内容:

\n\n

现在,我认为我们无法获取公钥文件来创建非对称密钥。它可能位于文件系统中的某个位置,因为它不应该是安全问题,作为“公共”密钥等等,但截至目前我不知道它在哪里。

\n

因此,目前我们应该仍然能够使用相同的基本技术来解决这个问题,该技术允许从 2017 之前的版本升级到 SQL Server 2017(或更高版本)的数据库中预先存在的未签名程序集正常工作:组装到位。当然,为了将程序集导入 SQL Server,我们需要暂时启用TRUSTWORTHY,但仅限于单个命令。然后,导入程序集后,我们可以:

\n
    \n
  1. 创建证书
  2. \n
  3. 用它签署程序集
  4. \n
  5. 将证书(公钥和私钥)备份到文件(无法通过 SQL Server 2012 中引入的CERTENCODEDVARBINARY获取公钥)
  6. \n
  7. 从证书中删除私钥,以便它不能用于签署其他任何内容
  8. \n
  9. 在 中创建相同的证书[master],但仅使用公钥(因此它不能用于签名)
  10. \n
  11. 从该证书创建登录
  12. \n
  13. 授予基于签名的登录UNSAFE ASSEMBLY权限
  14. \n
\n

根据上述步骤尝试以下方法。GRANT下面的示例代码假定创建非对称密钥、关联的基于签名的登录以及System.Messaging步骤已完成。

\n
--CREATE DATABASE [Test];\n--ALTER DATABASE [Test] SET RECOVERY SIMPLE;\nGO\n\nUSE [Test];\nALTER DATABASE [Test] SET TRUSTWORTHY ON;\n\nCREATE ASSEMBLY [System.Messaging]\nFROM \'C:\\Windows\\Microsoft.NET\\Framework\\v2.0.50727\\System.Messaging.dll\'\nWITH PERMISSION_SET = UNSAFE;\n\nALTER DATABASE [Test] SET TRUSTWORTHY OFF;\n\nSELECT * FROM sys.assemblies;\n-- System.Messaging: publickeytoken=b03f5f7f11d50a3a\n-- System.Windows.Forms: publickeytoken=b77a5c561934e089\n\nCREATE CERTIFICATE [WinForms]\n  ENCRYPTION BY PASSWORD = \'Use Another Password!\'\n  WITH SUBJECT = \'For ECMA-signed .NET Framework libraries\';\n\nADD SIGNATURE\n  TO ASSEMBLY::[System.Windows.Forms]\n  BY CERTIFICATE [WinForms] WITH PASSWORD = \'Use Another Password!\';\n\nBACKUP CERTIFICATE [WinForms]\n  TO FILE = \'C:\\TEMP\\WinFormsCert.crt\'\n  WITH PRIVATE KEY\n  (\n    FILE = \'C:\\TEMP\\WinFormsCert.pvk\',\n    ENCRYPTION BY PASSWORD = \'Backup Password!\',\n    DECRYPTION BY PASSWORD = \'Use Another Password!\'\n  );\n\nALTER CERTIFICATE [WinForms] REMOVE PRIVATE KEY;\nGO\n\nUSE [master];\nCREATE CERTIFICATE [WinForms] FROM FILE = \'C:\\TEMP\\WinFormsCert.crt\';\nCREATE LOGIN [WinForms] FROM CERTIFICATE [WinForms];\nGRANT UNSAFE ASSEMBLY TO [WinForms];\n
Run Code Online (Sandbox Code Playgroud)\n

使用 CLR 4.0(即 SQL Server 2012 及更高版本)时不需要此解决方法,因为所有这些程序集都使用证书进行签名。

\n

有关一般使用 SQLCLR 的更多信息,请访问:SQLCLR 信息

\n