Sql-Server

將 .Net 程序集添加到 SQL CLR 而不打開 TRUSTWORTHY ON

  • May 10, 2019

我正在嘗試使用 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

但是,當我執行此操作時,我得到了錯誤;

Msg 15208, Level 16, State 1, Line 1
The certificate, asymmetric key, or private key file does not exist or has invalid format.

我用來執行命令的帳戶具有“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

到目前為止一切都很好。我現在執行 CREATE ASSEMBLY 命令將程序集添加到 SQLCLR;

CREATE ASSEMBLY [System.Messaging]
FROM 'C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Messaging.dll'
WITH PERMISSION_SET = UNSAFE
GO

但這因錯誤而失敗;

為程序集“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

但這失敗了;

Msg 15468, Level 16, State 1, Line 1 在生成非對稱密鑰期間發生錯誤。

所以我嘗試了;

CREATE CERTIFICATE [Cer.System.Windows.Forms] FROM EXECUTABLE FILE = 'C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Windows.Forms.dll';
GO

這失敗了;

Msg 15208, Level 16, State 1, Line 1 證書、非對稱密鑰或私鑰文件不存在或格式無效。

所以現在我再次陷入困境,想知道是否可以在 SQL CLR 中使用 System.Messaging.dll 而無需啟用 TRUSTWORTHY 數據庫屬性*(以及為什麼 System.Messaging.dll 需要依賴於 System .Windows.Forms.dll!)*

感激地收到任何想法

我在 SQL Server 2017 CU12 上執行了相同的命令,得到了相同的 15208 錯誤。然後我嘗試了以下方法:

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

並且成功了!(名稱中的“snk”代表“強名稱密鑰”,因為從技術上講這不是證書)。

據我所知,CLR 2.0 的大多數 .NET Framework 庫(即 .NET Framework 2.0、3.0 和 3.5 版)都沒有使用證書籤名。大多數但不是全部的mscor*.dll文件,並且只有一個System.*.dllSystem.EnterpriseServices.Thunk.dll — 使用證書進行簽名。其餘的僅使用強名稱密鑰/強名稱。

從 CLR 4.0(即 .NET Framework 版本 4.)開始,似乎所有*.NET Framework 庫都使用證書進行簽名。

因此,更精確的規則是:

  • 對於 CLR 4.0(即 SQL Server 2012 和更高版本),請使用CREATE CERTIFICATE
  • 對於 CLR 2.0(即 SQL Server 版本 2005、2008 和 2008 R2),使用CREATE ASYMMETRIC KEY. 但是,如果這樣做會導致 15208 錯誤(“證書、非對稱密鑰或私鑰文件無效或不存在;或者您沒有權限”),則切換到CREATE CERTIFICATE.

這組開始的原因ASYMMETRIC KEY是需要使用的機率非常CERTIFICATE低。我嘗試在 SQL Server 2019(使用 CLR 4.0)和 SQL Server 2005(使用 CLR 2.0)中導入System.EnterpriseServices.Thunk.dll,但都失敗了——SQL Server 2005 中的 msg 6507 和 SQL 中的 msg 6544 Server 2019 — 抱怨“格式錯誤的程序集”(意味著它是混合模式/非純 MSIL 程序集)。我還嘗試在 SQL Server 2005 中導入一些mscor*庫,但它們因相同的 6507 錯誤而失敗(核心庫中包含非託管程式碼也就不足為奇了)。因此,很可能在CREATE CERTIFICATE為 CLR 2.0 導入 .NET Framework 庫時甚至沒有使用的可能性。

現在,System.Messaging似乎有幾個依賴項:

  • 系統配置安裝
  • system.runtime.serialization.formatters.soap
  • 系統.windows.forms
  • 系統繪圖
  • 可訪問性
  • system.directoryservices

這些依賴項會自動導入,因為源CREATE ASSEMBLY是文件而不是VARBINARY文字/十六進製字節。在執行依賴項的自動導入時,system.windows.forms上的操作失敗,聲稱它沒有被授權UNSAFE,即使我們已經創建了非對稱密鑰並且其他依賴項已經正確導入。

進一步調查顯示,用於system.windows.forms的強名稱密鑰與用於其他庫的不同。成功導入的庫的公鑰標記為 ,b03f5f7f11d50a3a而失敗的庫的公鑰標記為b77a5c561934e089正如 OP 發現的那樣,從system.windows.forms創建非對稱密鑰不起作用。從庫創建證書也不起作用,但這更容易解釋:庫沒有使用證書籤名;-)。然而,創建非對稱密鑰的問題可能是由於 system.windows.forms已簽署。它使用 ECMA 簽名,在庫中放置一個標準的佔位符值而不是公鑰,並且該佔位符值不是有效的公鑰。有關詳細資訊,請參閱以下內容:

現在,我認為我們無法獲取公鑰文件來創建非對稱密鑰。它可能在文件系統中的某個地方,因為它不應該是一個安全問題,是一個“公共”密鑰等等,但到目前為止我不知道它在哪裡。

因此,目前我們應該仍然能夠使用相同的基本技術來解決這個問題,該技術允許從 2017 之前的版本升級到 SQL Server 2017(或更高版本)的數據庫中預先存在的、未簽名的程序集工作:簽署就地組裝。當然,要將程序集放入 SQL Server 中,我們需要臨時啟用TRUSTWORTHY,但僅限於單個命令。然後,一旦程序集被導入,我們可以:

  1. 創建證書
  2. 用它簽署大會
  3. 將證書(公鑰和私鑰)備份到文件中(無法VARBINARY通過CERTENCODED獲取公鑰,因為它在 SQL Server 2012 中引入)
  4. 從證書中刪除私鑰,使其不能用於簽署其他任何內容
  5. 在 中創建相同的證書[master],但僅使用公鑰(因此不能用於簽名)
  6. 從該證書創建登錄
  7. 授予基於簽名的登錄UNSAFE ASSEMBLY權限

根據上述步驟嘗試以下方法。下面的範常式式碼假定創建非對稱密鑰、關聯的基於簽名的登錄和 System.Messaging 的步驟GRANT已經完成

--CREATE DATABASE [Test];
--ALTER DATABASE [Test] SET RECOVERY SIMPLE;
GO

USE [Test];
ALTER DATABASE [Test] SET TRUSTWORTHY ON;

CREATE ASSEMBLY [System.Messaging]
FROM 'C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Messaging.dll'
WITH PERMISSION_SET = UNSAFE;

ALTER DATABASE [Test] SET TRUSTWORTHY OFF;

SELECT * FROM sys.assemblies;
-- System.Messaging: publickeytoken=b03f5f7f11d50a3a
-- System.Windows.Forms: publickeytoken=b77a5c561934e089

CREATE CERTIFICATE [WinForms]
 ENCRYPTION BY PASSWORD = 'Use Another Password!'
 WITH SUBJECT = 'For ECMA-signed .NET Framework libraries';

ADD SIGNATURE
 TO ASSEMBLY::[System.Windows.Forms]
 BY CERTIFICATE [WinForms] WITH PASSWORD = 'Use Another Password!';

BACKUP CERTIFICATE [WinForms]
 TO FILE = 'C:\TEMP\WinFormsCert.crt'
 WITH PRIVATE KEY
 (
   FILE = 'C:\TEMP\WinFormsCert.pvk',
   ENCRYPTION BY PASSWORD = 'Backup Password!',
   DECRYPTION BY PASSWORD = 'Use Another Password!'
 );

ALTER CERTIFICATE [WinForms] REMOVE PRIVATE KEY;
GO

USE [master];
CREATE CERTIFICATE [WinForms] FROM FILE = 'C:\TEMP\WinFormsCert.crt';
CREATE LOGIN [WinForms] FROM CERTIFICATE [WinForms];
GRANT UNSAFE ASSEMBLY TO [WinForms];

在使用 CLR 4.0(即 SQL Server 2012 和更高版本)時,不需要這種解決方法,因為所有這些程序集都使用證書進行簽名。

有關一般使用 SQLCLR 的更多資訊,請訪問:SQLCLR 資訊

引用自:https://dba.stackexchange.com/questions/232411