Dot-Net

SQL Server 2017 上的 CLR 嚴格安全性

  • May 20, 2017

MSDN 在這篇文章上說:

CLR 使用 .NET Framework 中的程式碼訪問安全性 (CAS),不再支持將其作為安全邊界。使用 PERMISSION_SET = SAFE 創建的 CLR 程序集可能能夠訪問外部系統資源、呼叫非託管程式碼並獲得系統管理員權限。從 SQL Server 2017 開始,引入了一個名為 clr strict security 的 sp_configure 選項,以增強 CLR 程序集的安全性。預設情況下啟用 clr strict security,並將 SAFE 和 EXTERNAL_ACCESS 程序集視為標記為 UNSAFE。為了向後兼容,可以禁用 clr strict 安全選項,但不建議這樣做。Microsoft 建議使用證書或非對稱密鑰對所有程序集進行簽名,並使用已在 master 數據庫中授予 UNSAFE ASSEMBLY 權限的相應登錄名。

創建的 CLR 程序集如何PERMISSION_SET = SAFE能夠訪問外部系統資源、呼叫非託管程式碼並獲得系統管理員權限?

為什麼不再支持 CAS 作為安全邊界?

據我了解,CLR 程序集不再是安全的,這是非常不幸的。

使用 PERMISSION_SET = SAFE 創建的 CLR 程序集如何能夠訪問外部系統資源、呼叫非託管程式碼並獲得系統管理員權限?

這是由於從 4.5 版(我相信)開始在 .NET Framework 中進行的安全更改。

程式碼訪問安全基礎知識的 MSDN 文件指出:

.NET Framework 提供了一種機制,用於對執行在同一應用程序中的不同程式碼實施不同級別的信任,稱為程式碼訪問安全 (CAS)。.NET Framework 中的程式碼訪問安全性不應用作基於程式碼來源或其他身份方面強制實施安全邊界的機制。我們正在更新我們的指南,以反映程式碼訪問安全性和安全透明程式碼將不被支持作為部分受信任程式碼的安全邊界,尤其是未知來源的程式碼。我們建議不要在未採取替代安全措施的情況下載入和執行來源不明的程式碼。

然後指向.NET Framework 中的安全更改頁面,其中指出:

.NET Framework 4.5 中對安全性最重要的更改是強命名。

然後指向增強強命名的文件,其中指出:

強名稱密鑰由簽名密鑰和身份密鑰組成。程序集使用簽名密鑰進行簽名,並由身份密鑰標識。在 .NET Framework 4.5 之前,這兩個鍵是相同的。從 .NET Framework 4.5 開始,標識密鑰與早期 .NET Framework 版本中的相同,但簽名密鑰通過更強大的雜湊算法得到了增強。此外,簽名密鑰使用身份密鑰進行簽名以創建副簽名。

此外,安全編碼指南的文件指出:

不支持程式碼訪問安全性和安全透明程式碼作為部分受信任程式碼的安全邊界。我們建議不要在沒有採取替代安全措施的情況下載入和執行來源不明的程式碼……

因此,.NET 的安全模型幾年前發生了變化,但 SQL Server(直到 SQL Server 2017)已被允許繼續使用舊的安全模型。從 SQL Server 2017 開始,似乎決定不再支持舊的安全模型。

我懷疑允許舊的安全模型是:

  • 防止 SQL Server(至少是與 CLR 相關的功能/組件)基於較新的 .NET Framework 版本,以及
  • 負責從 Azure SQL 數據庫中突然刪除 SQLCLR 作為支持的功能(支持已在 2014 年底隨著 v12 的推出而添加,但隨後在 2016 年 4 月 15 日完全刪除)。

所以,是的,這有點糟糕。這意味著(至少目前)是需要首先創建一個證書或非對稱密鑰(已用於簽署要載入的任何程序集)[master],然後創建一個登錄名,然後授予UNSAFE ASSEMBLY該登錄名。EXTERNAL_ACCESS這與載入和程序集時需要執行的事件序列相同UNSAFE,但不幸的是,現在甚至需要為程序集完成SAFE

目前沒有機制以完全可移植的方式(即不依賴外部文件)處理此問題,並且在沒有手動干預的情況下無法由 Visual Studio / SSDT 處理。情況已經如此,但至少可以創建一個設置以完全可移植的方式處理此問題(即完全包含在 .sql 腳本中):請參閱SQLCLR 7 級的階梯:開發和安全了解詳細資訊(這是我寫的一篇文章)。

可以從十六進製字節FROM BINARY = 0x...signtoolsn.

為了使它可行,以便 Visual Studio / MSBuild / SSDT 發布過程正常工作(這反過來意味著任何人都可以創建一個完全獨立的 .sql 腳本,該腳本能夠創建非對稱密鑰而無需依賴外部文件),CREATE ASYMMETRIC KEY需要增強該命令以允許從二進製字元串創建。我在 Microsoft Connect 上提出了這個建議——允許從二進制十六進製字節字元串創建非對稱密鑰,就像 CREATE CERTIFICATE 一樣——所以請支持它:-)。

或者(目前,在 MS 希望創建更好的方法之前,例如我的非對稱密鑰建議),您可以嘗試我在以下部落格文章中描述的兩種技術中的任何一種(都可以完全使用 SSDT):

作為最後的手段,您可以考慮以下方法:

  1. 暫時[master]數據庫設置為TRUSTWORTHY ON

為使下一步(即CREATE ASSEMBLY)成功執行,作為數據庫所有者的登錄名(即與[dbo]使用者使用相同的 SID [master])需要具有UNSAFE ASSEMBLY權限。如果[master]sa或任何其他系統管理員擁有,則它具有所有權限並且已滿足此要求。但是,如果[master]由低權限登錄擁有(“最佳實踐”),那麼您將需要執行以下語句才能在isCREATE ASSEMBLY時工作:TRUSTWORTHY``ON

EXEC (N'USE [master]; GRANT UNSAFE ASSEMBLY TO [{DB_Owner_Login}];');
  1. 在中創建裝配體[master]
  2. 從程序集中創建非對稱密鑰
  3. 刪除程序集
  4. [master]數據庫設置為TRUSTWORTHY OFF
  5. 從非對稱密鑰創建登錄
  6. 授予UNSAFE ASSEMBLY該登錄名(這取代了將載入程序集的數據庫設置為TRUSTWORTHY ON 及其所有者登錄名具有UNSAFE ASSEMBLY權限的需要)。

請注意,我沒有此處包含新的“受信任的程序集”功能作為選項。沒有提到它的原因是它的缺陷多於好處,更不用說它完全沒有必要,因為現有功能已經處理了“受信任的程序集”旨在解決的情況。有關這方面的完整詳細資訊以及處理現有未簽名程序集的正確方法的展示,請參閱:SQLCLR 與 SQL Server 2017,第 4 部分:“受信任的程序集” - 失望

我知道這不是一個真正的解決方案,但您可以更改安全模式:

EXEC sp_configure 'show advanced options', 1
RECONFIGURE;
EXEC sp_configure 'clr strict security', 0;
RECONFIGURE;

對於那些想要繼續工作的人來說,這是最簡單的解決方案

引用自:https://stackoverflow.com/questions/44083098