


SQL Server2005SQLCLR代碼安全之權限
一、 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以便你能夠使用一個除了"上下文連接"串以外的連接-用以讀取當前實例中的數據,指定通常的服務器命名,憑證,等等。然而,我也無法找到為什么你要這樣做的理由,但是既然我們可以進行選擇,也是一件好事,對嗎?
(3) UNSAFE
這個UNSAFE權限集是賦予所有權限的SQLCLR等價物,在這種情況下,CLR掛起所有的許可權檢查。它接受單個的不受限制的SecurityPermission權限,這是CLR的授予所有權限的方式。
潛在地,一個UNSAFE程序集能夠完成各種"危險性"的動作,因為它屬于內在地被信任的代碼。例如,它能調用非托管代碼,例如COM組件和原始Win32 API。它還受限于服務帳戶的操作系統許可權,但是CLR不會限制它存取任何資源的能力。
因為UNSAFE是如此的不安全,所以,只有一個sysadmin能夠創建這種類型的程序集!
二、 訪問外部資源
因為訪問外部資源需要與操作系統進行交互,所以,當代碼嘗試存取外部的資源時,存在多種要遵守的規則。
對于SAFE代碼來說,這種規則是簡單的:如果它試圖存取一個外部的資源,那么存取將被否認并且它引發一個異常。就是這些。
對于EXTERNAL_ACCESS和UNSAFE的情況,則復雜些:
· 規則1:如果代碼在一個SQL Server登錄的安全上下文下執行(也就是說,還沒有被映射到一個Windows用戶或組),那么存取將被禁止并且引發一個異常。一個SQL登錄并不擁有SQL Server外的任何許可權,因此這是很重要的。
· 規則2:如果代碼在一個被映射到一個Windows登錄的登錄下執行,那么進行外部存取的執行上下文就是該登錄的執行上下文。如果該用戶能夠存取Windows中的資源,那么該代碼成功。如果不是,存取被否認并且引發一個異常。
· 規則3:如果調用者不是原始的調用者(已經進行了一個執行上下文切換),那么存取被否認并且引發一個異常。
一開始,這些規則也使我有點糊涂,但是,當我以后逐漸地越來越多地使用它們時,它們開始變得很重要了。對于規則1來說,因為一個SQL登錄僅僅存在于SQL Server世界中,所以,如果它能存取操作系統資源的話,這將是一個巨大的安全漏洞。規則2也很重要,并且它允許模擬。規則3似乎有點嚴格,但是我懷疑SQL Server小組有點保守,因為上下文切換可能會是一場"管理惡夢",并且他們仍然確信不會產生安全漏洞問題。
外部的存取規則甚至更復雜些。假定運行代碼的登錄已經成功"越過"上面列舉的"重重封鎖",但是,為了存取外部的資源-正如你可能盼望的(并且也許希望),SQL Server并不自動地模擬當前執行上下文。代之的是,它使用SQL Server實例的服務帳戶來存取資源。或者,你也可以顯式地模擬上下文登錄來存取資源。這樣做需要使用SqlContext對象的WindowsIdentity屬性來調用WindowsIdentity來實現實際的模擬。
列表1:在SQLCLR代碼中使用模擬
try
{
//模擬當前SQL安全上下文
WindowsIdentity CallerIdentity = SqlContext.WindowsIdentity;
if (CallerIdentity != null)
{
OriginalContext = CallerIdentity.Impersonate();
//做一些保護操作
}
}
catch
{
//從存取問題中恢復
}
finally
{
if (OriginalContext != null)
OriginalContext.Undo();
}
列表1向你展示如何在SQLCLR代碼中使用模擬。WindowsImpersonationContext對象屬于System.Security.Principal命名空間的一部分并且描述了在你模擬前的Windows用戶安全上下文。SqlContext對象屬于和SQL Server一起安裝的Microsoft.SQL Server.Server命名空間的一部分并且提供在SQL Server主機和SQLCLR代碼之間的一個鉤子。在這種情況中,它使用WindowsIdentity屬性來得到當前安全身份的一個令牌。這是Windows登錄的安全上下文-該代碼在這一登錄下運行。該代碼測試是否結果CallerIdentity為null,如果該代碼在一種SQL登錄下運行時它將為null。最后,它調用WindowsIdentity模擬來實現實際的模擬,并保存原始的上下文以用于當要求恢復到該上下文時。
必須理解,僅當執行需要保護的操作(例如打開一文件)時模擬才起作用。一旦它被打開,該代碼就不再需要模擬。因此,一旦你完成保護的操作,即恢復回去。
最后,通過調用OriginalContext的Undo方法,代碼塊負責恢復到原始上下文。如果你在函數結束之前不進行恢復,那么SQL Server將引發一個異常。
對于模擬也存在一些限制。當該模擬起作用時,你就無法再使用SQL Server實例存取數據或對象。在你再次存取本地數據之前,你必須恢復模擬。這也意味著,進程內數據存取總是發生在會話的當前安全上下文中。
有趣的是,一個異步執行的UNSAFE程序集(也就是說,它能夠創建線程并且異步地運行代碼)永遠不會允許進程內數據存取。其實,這并不是一個安全問題而顯然是一個可靠性的問題。
三、 可信賴的數據庫
在SAFE程序集和其它權限設置級別之間的另外一個區別是在SQL Server 2005測試期添加的,F在,你必須滿足兩個要求之一來創建EXTERNAL_ACCESS或UNSAFE程序集:
· 數據庫所有者(dbo)必須擁有EXTERNAL ACCESS ASSEMBLY權限并且數據庫必須擁有TRUSTWORTHY屬性集。
或者:
· 程序集的使用方式必須是,通過一個具有EXTERNAL ACCESS ASSEMBLY權限的登錄而且要使用一個證書或一個非對稱密鑰。
EXTERNAL ACCESS ASSEMBLY權限是另一種新的粒度許可權-允許一名負責人創建這類程序集。默認情況下,系統管理員擁有它并且能夠把它賦給其它登錄。但是這樣做時要慎重,這當然因為可能潛在地允許危險代碼安裝到服務器中。
一個數據庫的TRUSTWORTHY屬性要求設置管理員權限并且是在數據庫中安裝非SAFE程序集的前提;贓XTERNAL ACCESS ASSEMBLY權限,一個DBA能夠控制是否存在潛在危險性的程序集能夠被安裝到任何數據庫中,以及誰能夠把它們放到那里。這很有希望會使DBA安心而不必再擔心他們的服務器會感染.NET代碼!
四、 總結
表格3包含可用于SQLCLR程序集的三種權限集的總結,以及SQL Server為每種權限集提供的保護類型。
· 代碼存取安全是在代碼內CLR托管的許可權集。
· 編程模型限制是指宿主保護屬性,以及是否代碼能夠使用靜態技術。
· 要求確認指指,當你使用CREATE ASSEMBLY語句安裝它時是否SQL Server驗證代碼存在相對的安全性。
· 調用本機代碼指示,是否代碼能夠調用Win32 API或對外部組件作一種平臺調用。
表格3:權限設置總結。
權限集
保護類型 SAFE EXTERNAL_ACCESS UNSAFE
代碼存取安全 僅執行 執行和受限存取外部資源 不受限制
編程模型限制(主機保護屬性) 是 是 無
要求確認 是 是 否
調用本機代碼 否 否 是
如你所見,只要你把你的代碼限制為SAFE或EXTERNAL_ACCESS,SQL Server就能夠提供一種對保護數據安全和服務器穩定性的SQLCLR代碼的良好包裝。
下面是一個考察你對于SQLCLR安全的理解的測試:
· 可以使用一個常規的ADO.NET連接串來存取另一種數據庫(或者是一個Oracle或者是一個Access數據庫)嗎?
· 假定你現在已經了解訪問外部資源,存取一個Oracle數據庫的程序集需要具有什么樣的SQLCLR權限集級別?
在繼續閱讀之前,請認真地考慮一下這兩個問題吧。
提示 .NET框架中所包含的唯一的托管數據庫提供者是System.Data.SqlClient。
注意,這個程序集必須被安裝為UNSAFE。為什么呢?因為該代碼必須使用System.Data.OleDb對象。因為這些是基于COM的對象(這意味著是非托管代碼),所以程序集需要被安裝為UNSAFE-因為這是能夠存取非托管代碼的唯一的級別。
你可能認為這是微軟的與Oracle交互的方式。其實,答案是,對于訪問一個微軟Access數據庫也是一樣的,因為它也是基于OLE DB和相應的非托管代碼。
我將在此斗膽說一句:UNSAFE代碼永遠不應該用在一個生產服務器中。除非它是能夠被完全觀察的代碼和經過嚴格校驗以驗證它不會危害服務器;否則,你無法用一切辦法來足已保證它是安全的。盡管我不排除存在關于UNSAFE代碼的合法使用,但是我還是要深思熟慮到底是什么樣的代碼值得這樣一冒險。我通常感到,對于使用擴展的存儲過程也存在相同的問題,這一樣存在冒險性且必須以復雜的C++代碼來編寫。
至此,我可以說,任何允許UNSAFE代碼被安裝到一個生產服務器的DBA一般都應該是一個DBA高手而不是一個普通的DBA。而且,我認為,作為一名經常與DBA交流的開發人員,他們中的大多數都是高手!
但是,SAFE代碼不會比一個T-SQL存儲過程帶來更大的危險性,而且,當你需要存取外部資源時,EXTERNAL_ACCESS是一種合理的妥協。因此,你可以不必考慮對于未知內容的畏懼,而只需讓SAFE代碼加入到你的數據庫中好了。然后,當它對于數據庫、應用程序及用戶來說是重要的情況下,再考慮EXTERNAL_ACCESS代碼問題?傊谑沟眠@一類代碼安全和可靠方面,微軟的確做了一件好事情。
關鍵字:SQL Server、SQLCLR、數據庫
新文章:
- CentOS7下圖形配置網絡的方法
- CentOS 7如何添加刪除用戶
- 如何解決centos7雙系統后丟失windows啟動項
- CentOS單網卡如何批量添加不同IP段
- CentOS下iconv命令的介紹
- Centos7 SSH密鑰登陸及密碼密鑰雙重驗證詳解
- CentOS 7.1添加刪除用戶的方法
- CentOS查找/掃描局域網打印機IP講解
- CentOS7使用hostapd實現無AP模式的詳解
- su命令不能切換root的解決方法
- 解決VMware下CentOS7網絡重啟出錯
- 解決Centos7雙系統后丟失windows啟動項
- CentOS下如何避免文件覆蓋
- CentOS7和CentOS6系統有什么不同呢
- Centos 6.6默認iptable規則詳解