將 .Net 程序集添加到 SQL CLR 而不打開 TRUSTWORTHY ON
我正在嘗試使用 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.*.dll — System.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 簽名,在庫中放置一個標準的佔位符值而不是公鑰,並且該佔位符值不是有效的公鑰。有關詳細資訊,請參閱以下內容:
- 程序集和 GAC(Mono 項目;有 2 個與 ECMA 相關的定義)
- .NET 核心程序集中的非常特殊的 PublicKey(堆棧溢出答案)
現在,我認為我們無法獲取公鑰文件來創建非對稱密鑰。它可能在文件系統中的某個地方,因為它不應該是一個安全問題,是一個“公共”密鑰等等,但到目前為止我不知道它在哪裡。
因此,目前我們應該仍然能夠使用相同的基本技術來解決這個問題,該技術允許從 2017 之前的版本升級到 SQL Server 2017(或更高版本)的數據庫中預先存在的、未簽名的程序集工作:簽署就地組裝。當然,要將程序集放入 SQL Server 中,我們需要臨時啟用
TRUSTWORTHY
,但僅限於單個命令。然後,一旦程序集被導入,我們可以:
- 創建證書
- 用它簽署大會
- 將證書(公鑰和私鑰)備份到文件中(無法
VARBINARY
通過CERTENCODED獲取公鑰,因為它在 SQL Server 2012 中引入)- 從證書中刪除私鑰,使其不能用於簽署其他任何內容
- 在 中創建相同的證書
[master]
,但僅使用公鑰(因此不能用於簽名)- 從該證書創建登錄
- 授予基於簽名的登錄
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 資訊