一、SQLCLR權限集級別
當你使用CREATE ASSEMBLY語句把一個程序集加載到一個數據庫中時,SQL Server提供了三種權限集級別:SAFE,EXTERNAL_ACCESS和UNSAFE。這些權限集形成如圖3和圖5(均請參考第二篇)所示的AppDomain策略級別。
下面是一個典型的語句,它實現安裝位於FileLoader.dll文件內的一個程序集,並且賦予它EXTERNAL_ACCESS權限集。
CREATE ASSEMBLY FileAccess
FROM 'E:\FileLoader.dll'
WITH PERMISSION_SET = EXTERNAL_ACCESS
GO
在代碼執行時,每一種權限集級別都授予該代碼一組不同的CAS許可權集。下面讓我們開始討論在每一級上授予的特定許可權。
(1) SAFE
SAFE是默認的權限集。它僅授予足夠的許可權來執行代碼,實現不要求存取外部資源的內部計算以及存取在宿主SQL Server實例中的數據和對象。注意,SAFE代碼不能存取外部的資源,因此它不能讀取或寫磁盤文件,不能存取任何其它SQL Server實例,或讀取或寫注冊表。而且,該代碼也必須被檢驗為類型安全的,這將有助於避免各種包括緩沖區溢出在內的攻擊。
SAFE代碼是更可靠和安全的SQLCLR代碼。它能夠實現用T-SQL書寫的代碼在數據庫和服務器實例內所能實現的幾乎一樣的功能。它能夠授予如表格1所列舉的CAS許可權。從表格1中可見,該代碼能夠運行和讀取宿主SQL Server實例中的對象和數據-借助於一種特定形式的ADO.NET連接串,或者是"context connection=true"或者是"context connection=yes"來實現。任何其它連接串都可能會導致某種安全異常。
表格1:授予給SAFE程序集的權限集。
權限 類型 限制 SecurityPermission 受限制 執行 SqlClientPermission 受限制 不能是空口令,只能使用上下文連接串授予給一個程序集的結果權限集是列舉於表格1中的許可權權限集與來自企業、機器和用戶權限集的交集。因為這些級別默認會擁有所有的許可權,所以程序集僅接受列舉於表格1中的權限。注意,請確保你一定要理解這些權限。
(2) EXTERNAL_ACCESS
與SAFE相比,EXTERNAL_ACCESS權限集允許有限制地存取存在於SQL Server實例外部的資源-包括磁盤文件,在其它SQL Server實例中的數據和對象,環境變量和注冊表的一些部分。存取這些其它資源通常是在SQL Server服務帳戶的安全上下文中進行的,但是,該代碼能夠模擬其它用戶進行存取。這個級別授予列舉於表格2中的許可權。
表格2:授予給EXTERNAL_ACCESS程序集的權限集。
權限 類型 限制 EnviromentPermission 不受限制 - FileIOPermission 不受限制 - RegistryPermission 受限制 僅能以讀方式存取HKEY_CLASSES_ROOT,HKEY_LOCAL_MACHINE,HKEY_CURRENT_USER,HKEY_CURRENT_CONFIG和HKEY_USER SecurityPermission 受限制 Assertion,Execution,SerializationFormatter,ControlPrincipal KeyContainerPermission 不受限制 - SqlClientPermission 不受限制 - EventLogPermission 受限制 僅限於本地主機且僅限於系統管理員 DnsPermission 不受限制 - SocketPermission 受限制 僅限於IP地址 WebPermission 受限制 僅能通過HTTP存取本地主機 SmtpPermission 受限制 僅能進行連接存取 DistributedTransactionPermission 不受限制 - NetworkInformationPermission 受限制 僅能通過Ping方式存取 StorePermission 不受限制 -上面不受限制的FileIOPermission可能看起來有點令人擔心,因為,它意味著,從CLR的角度來看,代碼能存取磁盤上的任何位置。但是切記,該代碼仍然運行於本地服務帳戶的操作系統安全限制下。因此如果該帳戶不能存取一個文件的話,那麼SQLCLR代碼也不能存取。
典型地,本地服務帳戶是一種具有極強權限的帳戶,因此存在濫用的可能性。為此,我們一般把對這些程序集的存取權限僅授予那些具有服務帳戶信任度的登錄並且不使用本地系統帳戶作為SQL Server的服務帳戶。
值得注意的是,借助於EXTERNAL_ACCESS權限集,你可以使用一個更傳統型的ADO.NET連接串來連接到在同一個SQL Server實例(SQLCLR代碼在其中運行)中的一個數據庫。這需要SqlClientPermission以便你能夠使用一個除了"上下文連接"串以外的連接-用以讀取當前實例中的數據,指定通常的服務器命名,憑證,等等。然而,我也無法找到為什麼你要這樣做的理由,但是既然我們可以進行選擇,也是一件好事,對嗎?