是否可以在 SQL Server 2014 中为 .NET 框架程序集创建非对称密钥?

Is it possible to create an asymmetric key for a .NET framework assembly in SQL Server 2014?

我正在 Visual Studio 中开发一个 SQL 服务器数据库项目,它实际上是一个用户定义函数。在这个项目中,我包含了 Json.NET 作为参考(使用 NuGet)。

我设法通过首先打开数据库 TRUSTWORTHY ON(因为我的项目是不安全的)然后 运行宁此:

CREATE ASSEMBLY [System.Runtime.Serialization] 
FROM 'C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Runtime.Serialization.dll'
WITH PERMISSION_SET = UNSAFE;

结果是一个程序集Json.NET取决于(如果我不这样做,我会报错)

同时 I read about how bad turning TRUSTWORTHY ON can be and I tried to go the asymmetric key 避免打开它的方法。

甚至在签署我自己的程序集之前,我知道我必须为 System.Runtime.Serialization 创建一个密钥,因为我的项目依赖于 Json.Net 而后者又依赖于它,但是当我 运行 它,我明白了:

USE [master];
GO
  CREATE ASYMMETRIC KEY [SystemRuntimeSerializationKey]
    AUTHORIZATION [dbo]
    FROM EXECUTABLE FILE = 'C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Runtime.Serialization.dll';
GO

Msg 15468, Level 16, State 5, Line 3
An error occurred during the generation of the asymmetric key.

这对我帮助不大。

那么是否可以为 .NET 框架程序集生成这样的密钥,或者是否存在打开 TRUSTWORTHY 之外的解决方法?

不,我从未找到实现此目的的方法。用于签署 .NET Framework 程序集的密钥是 Microsoft 内部/私有的。尝试的选项:

  • 提取私钥/加载到 SQL 服务器:不可能,否则密钥不会是 "private"。签名/强命名系统是有效的,因为外人不能声称他们签署了代码。

  • 添加签名:我尝试使用 sn 实用程序添加一个新签名。由于以下原因无法正常工作:

    Failed to re-sign the assembly -- Public key of assembly did not match signing public key.

    但是,即使这确实有效,也可能并不意味着将其加载到 SQL 服务器中会有效,因为它与您作为资源添加到项目中的程序集不同。其他 .NET Framework DLL,如果有任何其他依赖项,将只知道原始签名。

  • 删除当前签名并添加一个新签名:我尝试使用 ILDASM 反汇编 System.Runtime.Serialization.dll,然后添加一个从 sn -k 创建的新私钥并然后使用 ILASM 重新链接,但在 ILASM 步骤失败(我没有时间进一步调查)。

    但是就像上面的选项一样,即使这确实有效,您也必须将 System.Runtime.Serialization 的 Json.NET 项目引用更改为这个新的 DLL,重新编译它,然后更改您的项目引用成为新的 DLL,然后重新编译它。但这只会让您能够干净地加载 DLL,如果它们具有需要原始 Microsoft 签名的外部依赖项,则不能保证它们能够正常工作。

本质上,如果您正在加载您无法控制签名的 DLL,那么唯一的希望就是使用 ILDASM 反编译并使用 ILASM 重新编译,指定新 snk 文件,但如果其他程序集链接到正在重新编译的内容,那将不起作用。当然 .NET Framework DLL 属于这一类。

简单地说:如果您要加载不受支持的 .NET Framework DLL,那么您几乎需要设置 TRUSTWORTHY ON.

但是:请记住,即使这确实可以通过非对称密钥或证书加载所有内容,但这并不意味着您不会 运行成功能性问题。这些库未被批准/验证是有原因的。它们中的代码可以以您不期望的方式工作,例如将数据存储到静态字段。在 Windows 和控制台应用程序中,这不是问题,因为每个应用程序域只使用一次。但是 SQLCLR 使用共享应用程序域,因此多个 SQL 服务器会话将共享这些静态变量。可能是 Json.NET 库调用的方法不使用那些不安全的东西,但没有办法知道,即使我们知道,现在我们也无能为力:-(。


我一直在考虑的一件事是跟踪在不受支持的 .NET Framework DLL 中调用的方法,并假设它没有做任何不安全的事情,将该代码直接复制到项目中。理论上应该可以工作,只要对 System.Runtime.Serialization 的调用不调用其他不受支持的 DLL 或做 "unsafe" 事情等。但是,我还没有时间对此进行测试。

我设法在 SQL Server 2014(版本 11.0.6248.0)上为 .Net Framework 4 Systen.Drawing.dll 执行此操作,使用以下脚本

USE MASTER
GO

CREATE 
    ASYMMETRIC KEY SystemDrawingKey 
    FROM EXECUTABLE FILE = N'C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Drawing.dll'   

CREATE 
    LOGIN SystemDrawingKeyLogin 
    FROM ASYMMETRIC KEY SystemDrawingKey   

GRANT UNSAFE ASSEMBLY TO SystemDrawingKeyLogin

USE MY_DATABASE
GO 

CREATE ASSEMBLY [SystemDrawing]
FROM N'C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Drawing.dll' WITH PERMISSION_SET = UNSAFE
GO 

SQL服务器接受这个程序集,但给出警告:

Warning: The Microsoft .NET Framework assembly 'system.drawing, version=4.0.0.0, culture=neutral, publickeytoken=b03f5f7f11d50a3a, processorarchitecture=msil.' you are registering is not fully tested in the SQL Server hosted environment and is not supported. In the future, if you upgrade or service this assembly or the .NET Framework, your CLR integration routine may stop working. Please refer SQL Server Books Online for more details.

为了验证 thustworthy 设置是否已关闭,我 运行 来自 A warning about the TRUSTWORTHY database option 的以下查询:

SELECT name, is_trustworthy_on
FROM sys.databases
WHERE name <> 'msdb'
AND is_trustworthy_on = 1

没有给出结果。当然,现在我有 WITH PERMISSION_SET = UNSAFE,但问题似乎少了。

System.Drawning.dll 是我需要第三方程序集的依赖项。我很确定我调用的方法不会调用 System.Drawing 中的任何内容,所以现在,我保持这种方式。

此外,我在创建自己的自定义程序集时遇到错误。我丢失了确切的错误,但提到了 Synchonization 并且它引用了 System.Diagnostics,这帮助我找到了对 Debug.WriteLine 的调用。删除之后,可以创建程序集并且一切正常。