SQL Server2005SQLCLR代碼安全之權(quán)限
一、 SQLCLR權(quán)限集級(jí)別
當(dāng)你使用CREATE ASSEMBLY語(yǔ)句把一個(gè)程序集加載到一個(gè)數(shù)據(jù)庫(kù)中時(shí),SQL Server提供了三種權(quán)限集級(jí)別:SAFE,EXTERNAL_ACCESS和UNSAFE。這些權(quán)限集形成如圖3和圖5(均請(qǐng)參考第二篇)所示的AppDomain策略級(jí)別。
下面是一個(gè)典型的語(yǔ)句,它實(shí)現(xiàn)安裝位于FileLoader.dll文件內(nèi)的一個(gè)程序集,并且賦予它EXTERNAL_ACCESS權(quán)限集。
CREATE ASSEMBLY FileAccess
FROM 'E:\FileLoader.dll'
WITH PERMISSION_SET = EXTERNAL_ACCESS
GO
在代碼執(zhí)行時(shí),每一種權(quán)限集級(jí)別都授予該代碼一組不同的CAS許可權(quán)集。下面讓我們開始討論在每一級(jí)上授予的特定許可權(quán)。
(1) SAFE
SAFE是默認(rèn)的權(quán)限集。它僅授予足夠的許可權(quán)來(lái)執(zhí)行代碼,實(shí)現(xiàn)不要求存取外部資源的內(nèi)部計(jì)算以及存取在宿主SQL Server實(shí)例中的數(shù)據(jù)和對(duì)象。注意,SAFE代碼不能存取外部的資源,因此它不能讀取或?qū)懘疟P文件,不能存取任何其它SQL Server實(shí)例,或讀取或?qū)懽?cè)表。而且,該代碼也必須被檢驗(yàn)為類型安全的,這將有助于避免各種包括緩沖區(qū)溢出在內(nèi)的攻擊。
SAFE代碼是更可靠和安全的SQLCLR代碼。它能夠?qū)崿F(xiàn)用T-SQL書寫的代碼在數(shù)據(jù)庫(kù)和服務(wù)器實(shí)例內(nèi)所能實(shí)現(xiàn)的幾乎一樣的功能。它能夠授予如表格1所列舉的CAS許可權(quán)。從表格1中可見,該代碼能夠運(yùn)行和讀取宿主SQL Server實(shí)例中的對(duì)象和數(shù)據(jù)-借助于一種特定形式的ADO.NET連接串,或者是"context connection=true"或者是"context connection=yes"來(lái)實(shí)現(xiàn)。任何其它連接串都可能會(huì)導(dǎo)致某種安全異常。
表格1:授予給SAFE程序集的權(quán)限集。
權(quán)限 類型 限制
SecurityPermission 受限制 執(zhí)行
SqlClientPermission 受限制 不能是空口令,只能使用上下文連接串
授予給一個(gè)程序集的結(jié)果權(quán)限集是列舉于表格1中的許可權(quán)權(quán)限集與來(lái)自企業(yè)、機(jī)器和用戶權(quán)限集的交集。因?yàn)檫@些級(jí)別默認(rèn)會(huì)擁有所有的許可權(quán),所以程序集僅接受列舉于表格1中的權(quán)限。注意,請(qǐng)確保你一定要理解這些權(quán)限。
(2) EXTERNAL_ACCESS
與SAFE相比,EXTERNAL_ACCESS權(quán)限集允許有限制地存取存在于SQL Server實(shí)例外部的資源-包括磁盤文件,在其它SQL Server實(shí)例中的數(shù)據(jù)和對(duì)象,環(huán)境變量和注冊(cè)表的一些部分。存取這些其它資源通常是在SQL Server服務(wù)帳戶的安全上下文中進(jìn)行的,但是,該代碼能夠模擬其它用戶進(jìn)行存取。這個(gè)級(jí)別授予列舉于表格2中的許可權(quán)。
表格2:授予給EXTERNAL_ACCESS程序集的權(quán)限集。
權(quán)限 類型 限制
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 受限制 僅限于本地主機(jī)且僅限于系統(tǒng)管理員
DnsPermission 不受限制 -
SocketPermission 受限制 僅限于IP地址
WebPermission 受限制 僅能通過(guò)HTTP存取本地主機(jī)
SmtpPermission 受限制 僅能進(jìn)行連接存取
DistributedTransactionPermission 不受限制 -
NetworkInformationPermission 受限制 僅能通過(guò)Ping方式存取
StorePermission 不受限制 -
上面不受限制的FileIOPermission可能看起來(lái)有點(diǎn)令人擔(dān)心,因?yàn)椋馕吨瑥腃LR的角度來(lái)看,代碼能存取磁盤上的任何位置。但是切記,該代碼仍然運(yùn)行于本地服務(wù)帳戶的操作系統(tǒng)安全限制下。因此如果該帳戶不能存取一個(gè)文件的話,那么SQLCLR代碼也不能存取。
典型地,本地服務(wù)帳戶是一種具有極強(qiáng)權(quán)限的帳戶,因此存在濫用的可能性。為此,我們一般把對(duì)這些程序集的存取權(quán)限僅授予那些具有服務(wù)帳戶信任度的登錄并且不使用本地系統(tǒng)帳戶作為SQL Server的服務(wù)帳戶。
值得注意的是,借助于EXTERNAL_ACCESS權(quán)限集,你可以使用一個(gè)更傳統(tǒng)型的ADO.NET連接串來(lái)連接到在同一個(gè)SQL Server實(shí)例(SQLCLR代碼在其中運(yùn)行)中的一個(gè)數(shù)據(jù)庫(kù)。這需要SqlClientPermission以便你能夠使用一個(gè)除了"上下文連接"串以外的連接-用以讀取當(dāng)前實(shí)例中的數(shù)據(jù),指定通常的服務(wù)器命名,憑證,等等。然而,我也無(wú)法找到為什么你要這樣做的理由,但是既然我們可以進(jìn)行選擇,也是一件好事,對(duì)嗎?
(3) UNSAFE
這個(gè)UNSAFE權(quán)限集是賦予所有權(quán)限的SQLCLR等價(jià)物,在這種情況下,CLR掛起所有的許可權(quán)檢查。它接受單個(gè)的不受限制的SecurityPermission權(quán)限,這是CLR的授予所有權(quán)限的方式。
潛在地,一個(gè)UNSAFE程序集能夠完成各種"危險(xiǎn)性"的動(dòng)作,因?yàn)樗鼘儆趦?nèi)在地被信任的代碼。例如,它能調(diào)用非托管代碼,例如COM組件和原始Win32 API。它還受限于服務(wù)帳戶的操作系統(tǒng)許可權(quán),但是CLR不會(huì)限制它存取任何資源的能力。
因?yàn)閁NSAFE是如此的不安全,所以,只有一個(gè)sysadmin能夠創(chuàng)建這種類型的程序集。
二、 訪問(wèn)外部資源
因?yàn)樵L問(wèn)外部資源需要與操作系統(tǒng)進(jìn)行交互,所以,當(dāng)代碼嘗試存取外部的資源時(shí),存在多種要遵守的規(guī)則。
對(duì)于SAFE代碼來(lái)說(shuō),這種規(guī)則是簡(jiǎn)單的:如果它試圖存取一個(gè)外部的資源,那么存取將被否認(rèn)并且它引發(fā)一個(gè)異常。就是這些。
對(duì)于EXTERNAL_ACCESS和UNSAFE的情況,則復(fù)雜些:
· 規(guī)則1:如果代碼在一個(gè)SQL Server登錄的安全上下文下執(zhí)行(也就是說(shuō),還沒(méi)有被映射到一個(gè)Windows用戶或組),那么存取將被禁止并且引發(fā)一個(gè)異常。一個(gè)SQL登錄并不擁有SQL Server外的任何許可權(quán),因此這是很重要的。
· 規(guī)則2:如果代碼在一個(gè)被映射到一個(gè)Windows登錄的登錄下執(zhí)行,那么進(jìn)行外部存取的執(zhí)行上下文就是該登錄的執(zhí)行上下文。如果該用戶能夠存取Windows中的資源,那么該代碼成功。如果不是,存取被否認(rèn)并且引發(fā)一個(gè)異常。
· 規(guī)則3:如果調(diào)用者不是原始的調(diào)用者(已經(jīng)進(jìn)行了一個(gè)執(zhí)行上下文切換),那么存取被否認(rèn)并且引發(fā)一個(gè)異常。
一開始,這些規(guī)則也使我有點(diǎn)糊涂,但是,當(dāng)我以后逐漸地越來(lái)越多地使用它們時(shí),它們開始變得很重要了。對(duì)于規(guī)則1來(lái)說(shuō),因?yàn)橐粋(gè)SQL登錄僅僅存在于SQL Server世界中,所以,如果它能存取操作系統(tǒng)資源的話,這將是一個(gè)巨大的安全漏洞。規(guī)則2也很重要,并且它允許模擬。規(guī)則3似乎有點(diǎn)嚴(yán)格,但是我懷疑SQL Server小組有點(diǎn)保守,因?yàn)樯舷挛那袚Q可能會(huì)是一場(chǎng)"管理惡夢(mèng)",并且他們?nèi)匀淮_信不會(huì)產(chǎn)生安全漏洞問(wèn)題。
外部的存取規(guī)則甚至更復(fù)雜些。假定運(yùn)行代碼的登錄已經(jīng)成功"越過(guò)"上面列舉的"重重封鎖",但是,為了存取外部的資源-正如你可能盼望的(并且也許希望),SQL Server并不自動(dòng)地模擬當(dāng)前執(zhí)行上下文。代之的是,它使用SQL Server實(shí)例的服務(wù)帳戶來(lái)存取資源。或者,你也可以顯式地模擬上下文登錄來(lái)存取資源。這樣做需要使用SqlContext對(duì)象的WindowsIdentity屬性來(lái)調(diào)用WindowsIdentity來(lái)實(shí)現(xiàn)實(shí)際的模擬。
列表1:在SQLCLR代碼中使用模擬
try
{
//模擬當(dāng)前SQL安全上下文
WindowsIdentity CallerIdentity = SqlContext.WindowsIdentity;
if (CallerIdentity != null)
{
OriginalContext = CallerIdentity.Impersonate();
//做一些保護(hù)操作
}
}
catch
{
//從存取問(wèn)題中恢復(fù)
}
finally
{
if (OriginalContext != null)
OriginalContext.Undo();
}
列表1向你展示如何在SQLCLR代碼中使用模擬。WindowsImpersonationContext對(duì)象屬于System.Security.Principal命名空間的一部分并且描述了在你模擬前的Windows用戶安全上下文。SqlContext對(duì)象屬于和SQL Server一起安裝的Microsoft.SQL Server.Server命名空間的一部分并且提供在SQL Server主機(jī)和SQLCLR代碼之間的一個(gè)鉤子。在這種情況中,它使用WindowsIdentity屬性來(lái)得到當(dāng)前安全身份的一個(gè)令牌。這是Windows登錄的安全上下文-該代碼在這一登錄下運(yùn)行。該代碼測(cè)試是否結(jié)果CallerIdentity為null,如果該代碼在一種SQL登錄下運(yùn)行時(shí)它將為null。最后,它調(diào)用WindowsIdentity模擬來(lái)實(shí)現(xiàn)實(shí)際的模擬,并保存原始的上下文以用于當(dāng)要求恢復(fù)到該上下文時(shí)。
必須理解,僅當(dāng)執(zhí)行需要保護(hù)的操作(例如打開一文件)時(shí)模擬才起作用。一旦它被打開,該代碼就不再需要模擬。因此,一旦你完成保護(hù)的操作,即恢復(fù)回去。
最后,通過(guò)調(diào)用OriginalContext的Undo方法,代碼塊負(fù)責(zé)恢復(fù)到原始上下文。如果你在函數(shù)結(jié)束之前不進(jìn)行恢復(fù),那么SQL Server將引發(fā)一個(gè)異常。
對(duì)于模擬也存在一些限制。當(dāng)該模擬起作用時(shí),你就無(wú)法再使用SQL Server實(shí)例存取數(shù)據(jù)或?qū)ο蟆T谀阍俅未嫒”镜財(cái)?shù)據(jù)之前,你必須恢復(fù)模擬。這也意味著,進(jìn)程內(nèi)數(shù)據(jù)存取總是發(fā)生在會(huì)話的當(dāng)前安全上下文中。
有趣的是,一個(gè)異步執(zhí)行的UNSAFE程序集(也就是說(shuō),它能夠創(chuàng)建線程并且異步地運(yùn)行代碼)永遠(yuǎn)不會(huì)允許進(jìn)程內(nèi)數(shù)據(jù)存取。其實(shí),這并不是一個(gè)安全問(wèn)題而顯然是一個(gè)可靠性的問(wèn)題。
三、 可信賴的數(shù)據(jù)庫(kù)
在SAFE程序集和其它權(quán)限設(shè)置級(jí)別之間的另外一個(gè)區(qū)別是在SQL Server 2005測(cè)試期添加的。現(xiàn)在,你必須滿足兩個(gè)要求之一來(lái)創(chuàng)建EXTERNAL_ACCESS或UNSAFE程序集:
· 數(shù)據(jù)庫(kù)所有者(dbo)必須擁有EXTERNAL ACCESS ASSEMBLY權(quán)限并且數(shù)據(jù)庫(kù)必須擁有TRUSTWORTHY屬性集。
或者:
· 程序集的使用方式必須是,通過(guò)一個(gè)具有EXTERNAL ACCESS ASSEMBLY權(quán)限的登錄而且要使用一個(gè)證書或一個(gè)非對(duì)稱密鑰。
EXTERNAL ACCESS ASSEMBLY權(quán)限是另一種新的粒度許可權(quán)-允許一名負(fù)責(zé)人創(chuàng)建這類程序集。默認(rèn)情況下,系統(tǒng)管理員擁有它并且能夠把它賦給其它登錄。但是這樣做時(shí)要慎重,這當(dāng)然因?yàn)榭赡軡撛诘卦试S危險(xiǎn)代碼安裝到服務(wù)器中。
一個(gè)數(shù)據(jù)庫(kù)的TRUSTWORTHY屬性要求設(shè)置管理員權(quán)限并且是在數(shù)據(jù)庫(kù)中安裝非SAFE程序集的前提。基于EXTERNAL ACCESS ASSEMBLY權(quán)限,一個(gè)DBA能夠控制是否存在潛在危險(xiǎn)性的程序集能夠被安裝到任何數(shù)據(jù)庫(kù)中,以及誰(shuí)能夠把它們放到那里。這很有希望會(huì)使DBA安心而不必再擔(dān)心他們的服務(wù)器會(huì)感染.NET代碼!
四、 總結(jié)
表格3包含可用于SQLCLR程序集的三種權(quán)限集的總結(jié),以及SQL Server為每種權(quán)限集提供的保護(hù)類型。
· 代碼存取安全是在代碼內(nèi)CLR托管的許可權(quán)集。
· 編程模型限制是指宿主保護(hù)屬性,以及是否代碼能夠使用靜態(tài)技術(shù)。
· 要求確認(rèn)指指,當(dāng)你使用CREATE ASSEMBLY語(yǔ)句安裝它時(shí)是否SQL Server驗(yàn)證代碼存在相對(duì)的安全性。
· 調(diào)用本機(jī)代碼指示,是否代碼能夠調(diào)用Win32 API或?qū)ν獠拷M件作一種平臺(tái)調(diào)用。
表格3:權(quán)限設(shè)置總結(jié)。
權(quán)限集
保護(hù)類型 SAFE EXTERNAL_ACCESS UNSAFE
代碼存取安全 僅執(zhí)行 執(zhí)行和受限存取外部資源 不受限制
編程模型限制(主機(jī)保護(hù)屬性) 是 是 無(wú)
要求確認(rèn) 是 是 否
調(diào)用本機(jī)代碼 否 否 是
如你所見,只要你把你的代碼限制為SAFE或EXTERNAL_ACCESS,SQL Server就能夠提供一種對(duì)保護(hù)數(shù)據(jù)安全和服務(wù)器穩(wěn)定性的SQLCLR代碼的良好包裝。
下面是一個(gè)考察你對(duì)于SQLCLR安全的理解的測(cè)試:
· 可以使用一個(gè)常規(guī)的ADO.NET連接串來(lái)存取另一種數(shù)據(jù)庫(kù)(或者是一個(gè)Oracle或者是一個(gè)Access數(shù)據(jù)庫(kù))嗎?
· 假定你現(xiàn)在已經(jīng)了解訪問(wèn)外部資源,存取一個(gè)Oracle數(shù)據(jù)庫(kù)的程序集需要具有什么樣的SQLCLR權(quán)限集級(jí)別?
在繼續(xù)閱讀之前,請(qǐng)認(rèn)真地考慮一下這兩個(gè)問(wèn)題吧。
提示 .NET框架中所包含的唯一的托管數(shù)據(jù)庫(kù)提供者是System.Data.SqlClient。
注意,這個(gè)程序集必須被安裝為UNSAFE。為什么呢?因?yàn)樵摯a必須使用System.Data.OleDb對(duì)象。因?yàn)檫@些是基于COM的對(duì)象(這意味著是非托管代碼),所以程序集需要被安裝為UNSAFE-因?yàn)檫@是能夠存取非托管代碼的唯一的級(jí)別。
你可能認(rèn)為這是微軟的與Oracle交互的方式。其實(shí),答案是,對(duì)于訪問(wèn)一個(gè)微軟Access數(shù)據(jù)庫(kù)也是一樣的,因?yàn)樗彩腔贠LE DB和相應(yīng)的非托管代碼。
我將在此斗膽說(shuō)一句:UNSAFE代碼永遠(yuǎn)不應(yīng)該用在一個(gè)生產(chǎn)服務(wù)器中。除非它是能夠被完全觀察的代碼和經(jīng)過(guò)嚴(yán)格校驗(yàn)以驗(yàn)證它不會(huì)危害服務(wù)器;否則,你無(wú)法用一切辦法來(lái)足已保證它是安全的。盡管我不排除存在關(guān)于UNSAFE代碼的合法使用,但是我還是要深思熟慮到底是什么樣的代碼值得這樣一冒險(xiǎn)。我通常感到,對(duì)于使用擴(kuò)展的存儲(chǔ)過(guò)程也存在相同的問(wèn)題,這一樣存在冒險(xiǎn)性且必須以復(fù)雜的C++代碼來(lái)編寫。
至此,我可以說(shuō),任何允許UNSAFE代碼被安裝到一個(gè)生產(chǎn)服務(wù)器的DBA一般都應(yīng)該是一個(gè)DBA高手而不是一個(gè)普通的DBA。而且,我認(rèn)為,作為一名經(jīng)常與DBA交流的開發(fā)人員,他們中的大多數(shù)都是高手!
但是,SAFE代碼不會(huì)比一個(gè)T-SQL存儲(chǔ)過(guò)程帶來(lái)更大的危險(xiǎn)性,而且,當(dāng)你需要存取外部資源時(shí),EXTERNAL_ACCESS是一種合理的妥協(xié)。因此,你可以不必考慮對(duì)于未知內(nèi)容的畏懼,而只需讓SAFE代碼加入到你的數(shù)據(jù)庫(kù)中好了。然后,當(dāng)它對(duì)于數(shù)據(jù)庫(kù)、應(yīng)用程序及用戶來(lái)說(shuō)是重要的情況下,再考慮EXTERNAL_ACCESS代碼問(wèn)題。總之,在使得這一類代碼安全和可靠方面,微軟的確做了一件好事情。
關(guān)鍵字:SQL Server、SQLCLR、數(shù)據(jù)庫(kù)
新文章:
- CentOS7下圖形配置網(wǎng)絡(luò)的方法
- CentOS 7如何添加刪除用戶
- 如何解決centos7雙系統(tǒng)后丟失windows啟動(dòng)項(xiàng)
- CentOS單網(wǎng)卡如何批量添加不同IP段
- CentOS下iconv命令的介紹
- Centos7 SSH密鑰登陸及密碼密鑰雙重驗(yàn)證詳解
- CentOS 7.1添加刪除用戶的方法
- CentOS查找/掃描局域網(wǎng)打印機(jī)IP講解
- CentOS7使用hostapd實(shí)現(xiàn)無(wú)AP模式的詳解
- su命令不能切換root的解決方法
- 解決VMware下CentOS7網(wǎng)絡(luò)重啟出錯(cuò)
- 解決Centos7雙系統(tǒng)后丟失windows啟動(dòng)項(xiàng)
- CentOS下如何避免文件覆蓋
- CentOS7和CentOS6系統(tǒng)有什么不同呢
- Centos 6.6默認(rèn)iptable規(guī)則詳解