智能客戶端體系結構與設計指南
David Hill, Brenton Webster, Edward A. Jezierski, Srinath Vasireddy and Mohammad Al-Sabt, Microsoft Corporation; Blaine Wastell, Ascentium Corporation; Jonathan Rasmusson and Paul Gale, ThoughtWorks; and Paul Slater, Wadeware LLC
相關鏈接
Microsoft? patterns & practices 庫
http://www.microsoft.com/resources/practices/default.mspx.NET 的應用程序體系結構:設計應用程序和服務
http://msdn.microsoft.com/library/en-us/dnbda/html/distapp.asp摘要:本章介紹智能客戶端的安全性問題。智能客戶端將邏輯和數(shù)據(jù)分布到客戶端計算機;因此需要考慮的安全性和與瘦客戶端應用程序相關的安全性是不同的,后者的數(shù)據(jù)和邏輯更多地被限制到服務器。本章討論智能客戶端應用程序中的數(shù)據(jù)安全性、身份驗證、授權以及代碼訪問角色的安全性。
智能客戶端是分布式應用程序,通??缭蕉喾N不同的產(chǎn)品和技術。管理這些應用程序中的安全性是一件極具挑戰(zhàn)性的事情。在服務器端,需要采用一種方法來保護網(wǎng)絡、服務器本身及其應用程序。在客戶端,應集中于利用平臺(其中包括操作系統(tǒng)和 Microsoft? .NET Framework)的安全特性、客戶端代碼可以執(zhí)行的特權操作(代碼訪問安全)以及與服務器平臺(域)和服務器應用程序的交互。
有效的安全性取決于深層防御方法。在保護智能客戶端時,考慮安全性的各個方面非常重要,其中包括以下幾個方面:
?
身份驗證。這唯一地標識了客戶端應用程序的用戶,從而只有經(jīng)過認可的用戶才能訪問應用程序的全部或部分。
?
授權。這確定唯一標識的用戶可以執(zhí)行的操作。這些操作可以是任務,也可以是對授予經(jīng)過身份驗證的用戶訪問權限的資源進行的操作。
?
數(shù)據(jù)驗證。這確保只有適當?shù)暮陀行У臄?shù)據(jù)才能被應用程序接受。如果允許任何用戶輸入而不首先驗證數(shù)據(jù),則攻擊者就可以通過插入惡意的輸入來危及應用程序的安全。
?
保護敏感數(shù)據(jù)。這意味著確保應用程序存儲和傳輸?shù)拿舾袛?shù)據(jù)(例如密碼或機密的商業(yè)數(shù)據(jù))是安全的。對敏感數(shù)據(jù)進行加密可以確保數(shù)據(jù)不可能以明文形式獲得;取決于算法的選擇,這還可以確保信息不會被篡改,從而維護其完整性。
?
審核和日志記錄。這包括保存對事件和用戶操作的記錄。應該考慮將關鍵的用戶操作或活動記錄在服務器上,或者安全地記錄在客戶端上,因為客戶端計算機上的日志可能被篡改或清除。
?
異常管理。這確保應用程序適當?shù)靥幚懋惓:褪?,并且返回用戶友好的非敏感信息。異常詳細信息可以記錄到事件日志或應用程序日志中?div style="height:15px;">
?
更改和配置管理。這確保跟蹤 IT 環(huán)境的配置以及對其進行的任何更改。通過這樣做,可以查看是否出現(xiàn)任何未經(jīng)授權的更改,并且確定任何經(jīng)授權的更改所涉及的安全性含義。
本章詳細描述了在設計智能客戶端應用程序時將會面臨的一些關鍵安全性問題,具體來說,重點介紹了身份驗證、授權、數(shù)據(jù)驗證和保護敏感數(shù)據(jù)。同時,本章還介紹了代碼訪問安全,它是 .NET Framework 中的一項關鍵技術,用于管理代碼級而非用戶級安全性。
在檢驗智能客戶端安全性時還需要考慮的另一個重要方面是如何部署智能客戶端。有關影響部署的安全性問題的詳細信息,請參閱
第 7 章:智能客戶端的部署與更新。
注在應用程序中使用的任何代碼都應該使用 FxCop 進行分析。通過這個工具,可以檢查托管代碼程序集是否符合 .NET Framework 設計指導原則,其中包括符合基本級別的安全性??梢詮?GotDotNet 站點
http://www.gotdotnet.com/team/fxcop/ 下載 FxCop。
身份驗證
身份驗證是通過檢驗他的或她的憑據(jù)來唯一標識用戶的過程。當用戶試圖運行或安裝應用程序時,或者當應用程序建立到遠程服務的連接或訪問本地保存的數(shù)據(jù)時,都可能需要用戶身份驗證。
這一節(jié)分析智能客戶端常見的一些身份驗證方案,介紹對網(wǎng)絡調(diào)用進行身份驗證的幾種不同方式,并討論如何收集用戶憑據(jù)和在脫機時檢驗這些憑據(jù)。
智能客戶端身份驗證方案
取決于智能客戶端應用程序的樣式和功能,在用戶與應用程序交互的過程中,可能需要在一個或多個階段對用戶進行身份驗證。對用戶進行身份驗證可供選擇的階段有四個:
?
在應用程序安裝時
?
在應用程序運行時
?
在用戶訪問本地保存的敏感數(shù)據(jù)時
?
在用戶通過網(wǎng)絡訪問外部服務時
經(jīng)過身份驗證的安裝
如果應用程序是集中部署的(例如,使用無接觸部署),則可能需要保護 Web 服務器上的應用程序,以便只有經(jīng)過授權的用戶才能安裝它們。這些用戶必須首先經(jīng)過 Web 服務器的身份驗證,Web 服務器查看他們是否被授權訪問該應用程序和將其下載到他們的客戶端計算機上。
保護對無接觸部署的智能客戶端應用程序的訪問與保護任何其他位于 Web 服務器的構件(例如 Web 頁面)相似。Microsoft Internet Information Services (IIS) 提供了許多身份驗證機制,例如集成 Windows、摘要或基本身份驗證。
注如果使用無接觸部署并且應用程序使用配置文件來存儲它的配置設置,則不適合使用摘要和基本身份驗證,因為 .NET Framework 不能使用這些機制自動下載配置文件。
在選擇適當?shù)纳矸蒡炞C機制并且 IIS 可以根據(jù)他的或她的憑據(jù)標識用戶之后,就可以通過設置應用程序和程序集文件上的文件權限來保護應用程序及其依賴程序集。為了簡化對大量用戶的管理,可以考慮提供對 Microsoft Windows 組(例如 SmartClientAppUsers)的訪問,并將各個用戶放在這個組中。
所有需要進行身份驗證的用戶都必須具有服務器上的 Windows 標識,這樣 IIS 就可以保護對應用程序及其程序集的訪問,但是他們未必需要使用這一標識登錄到他們的客戶端計算機上。如果用戶的登錄帳戶不為服務器端所知,則當他或她單擊指向應用程序的可執(zhí)行文件的鏈接時,系統(tǒng)就會提示用戶輸入用戶名和密碼。
如果使用集成 Windows 身份驗證,則系統(tǒng)就會自動使用已登錄用戶的憑據(jù)來嘗試獲取對應用程序的訪問權限。當用戶通過為客戶端和服務器所共有的標識登錄時,就可以進行無縫且安全的訪問。
經(jīng)過身份驗證的應用程序訪問
對安裝應用程序的用戶進行身份驗證可以確保,只有經(jīng)過身份驗證和授權的用戶才能從中心位置運行應用程序。然而,因為應用程序及其依賴構件可能緩存在客戶端計算機上,所以不能在應用程序每次運行時都依賴于這一機制來對用戶進行身份驗證。在這種情況下,或者當用戶有意在本地部署應用程序時,就需要仔細考慮如何通過應用程序對用戶進行身份驗證??赡苄枰谟脩裘看芜\行應用程序時就對他們進行身份驗證,特別是如果應用程序提供敏感功能,或者需要能夠撤消用戶在任何時候運行應用程序的授權。
在用戶使用為客戶端和服務器所共有的標識登錄到客戶端計算機的情況下,可以依賴用戶能夠登錄客戶端計算機的事實,并以此作為對運行應用程序的充分身份驗證。通過這種方法,可以使用 Microsoft Windows 操作系統(tǒng)來提供用戶身份驗證,從而使得不必需要用代碼實現(xiàn)用戶身份驗證。另外,因為 Windows 可以在脫機時緩存用戶憑據(jù),所以您不需要自己緩存它們。
對于您對用戶訪問沒有任何控制的客戶端計算機(例如您的組織的 intranet 外的客戶端計算機),您可能需要采用一種自定義身份驗證機制來收集用戶憑據(jù),并且根據(jù)遠程安全性授權對他們進行身份驗證。如果應用程序能夠脫機操作,您就需要在客戶端緩存有效的憑據(jù),這樣,當他或她啟動應用程序時,您就可以根據(jù)它們重新對用戶進行身份驗證。您應該定期強制執(zhí)行聯(lián)機重新身份驗證,這樣就可以防止對這樣的應用程序的無限制使用。
經(jīng)過身份驗證的本地數(shù)據(jù)訪問
智能客戶端應用程序常常緩存從遠程服務獲得的數(shù)據(jù)(例如,為了提高響應速度或者為了支持脫機功能)。如果數(shù)據(jù)是敏感的,則可能需要在授予用戶訪問數(shù)據(jù)的權限之前對其進行身份驗證。在這種情況下,可以選擇允許未經(jīng)身份驗證的用戶運行應用程序,但是需要在授予用戶訪問敏感數(shù)據(jù)的權限之前對其進行充分的身份驗證和授權。
注確保只有授權用戶訪問的數(shù)據(jù)才能在本地緩存非常重要。如果數(shù)據(jù)是敏感的,則還需要確保采取足夠的措施來保證數(shù)據(jù)的安全。詳細信息請參閱本章后面的“處理敏感數(shù)據(jù)”。本地保存的數(shù)據(jù)應該保存在安全的位置并進行加密。不管如何對用戶進行身份驗證,通常都需要以某種方式使用他們的憑據(jù)來訪問和解密數(shù)據(jù)。
您可能能夠使用用于登錄到客戶端計算機的默認憑據(jù),也可能需要獲得自定義憑據(jù)來根據(jù)遠程安全性授權對用戶進行身份驗證。對于在 intranet 環(huán)境中運行的應用程序,前一種方式最為合適,而對于在 Internet 或外部網(wǎng)環(huán)境中運行的應用程序,由于用戶通常不在與他們訪問的遠程服務相同的域中,所以后一種方式比較合適。使用集成 Windows 身份驗證的一個好處是,操作系統(tǒng)可以對用戶進行身份驗證,保護應用程序和本地數(shù)據(jù),并且可以在用戶脫機時緩存用戶憑據(jù)。
有關在本地緩存敏感數(shù)據(jù)的詳細信息,請參閱本章后面的“處理敏感數(shù)據(jù)”。
經(jīng)過身份驗證的網(wǎng)絡訪問
您可能會選擇支持對應用程序的匿名訪問并允許任何用戶下載和運行它。然而,在應用程序運行在客戶端之后,它通常需要通過網(wǎng)絡訪問遠程服務(例如 Web 服務)以獲得數(shù)據(jù)和服務。
通常需要保護對網(wǎng)絡數(shù)據(jù)和服務的訪問,以防止未經(jīng)授權的訪問。保護遠程服務訪問的方式可能有許多種,但通常需要將用戶憑據(jù)傳送到遠程服務,以便它可以執(zhí)行用戶身份驗證。
當用戶通過網(wǎng)絡訪問遠程服務時對他們進行身份驗證是一項非常重要的內(nèi)容。本章后面的“網(wǎng)絡訪問身份驗證類型”比較完整地描述了確保對網(wǎng)絡服務調(diào)用進行身份驗證的一些選擇。
選擇正確的身份驗證模型
前一節(jié)描述了您可能選擇用來對用戶進行身份驗證的四個階段。您可能選擇在一個或多個階段對用戶進行身份驗證,這取決于您的應用程序及其功能的性質。選擇正確的階段是非常重要的,它既可以幫助確保應用程序和數(shù)據(jù)的安全,又可以將對應用程序的使用的任何影響降低到最低限度。
如果您的應用程序是集中部署的(例如,如果使用無接觸部署進行部署,或者部署到文件共享),則您可能選擇將訪問僅限于經(jīng)過授權的用戶。如果您想讓您的應用程序對任何想要使用它的人都可用,則不需要在安裝應用程序時對用戶進行身份驗證。
客戶端計算機通常在物理上并不安全,甚至可能能夠進行公開訪問。如果是這種情況,并且應用程序提供敏感功能,則往往需要在應用程序運行時對用戶進行身份驗證。如果應用程序提供的是匿名用戶可用的常規(guī)功能,則不需要在這一階段對用戶進行身份驗證。然而,您可能會選擇給匿名用戶提供應用程序的部分功能,但是需要在允許他們訪問更多受限功能之前對其進行身份驗證。
保護對本地保存的敏感數(shù)據(jù)的訪問非常重要。如果應用程序部署在物理上不安全或者可以公開訪問的設備上,則應該對敏感數(shù)據(jù)進行保護,并且只有經(jīng)過身份驗證和授權的用戶才能訪問它們。應用程序可以給匿名用戶提供常規(guī)功能,但是在用戶試圖訪問敏感數(shù)據(jù)時需要對他們進行身份驗證。
在應用程序脫機運行時,使用集成 Windows 身份驗證也有好處。在這種情況下,Windows 緩存用戶憑據(jù),以便當用戶登錄到脫機客戶端計算機時對他(她)進行身份驗證。如果您需要在應用程序運行或訪問本地保存的敏感數(shù)據(jù)時對用戶進行身份驗證,則這一行為使得您的客戶端不需要對用戶進行身份驗證。
網(wǎng)絡訪問身份驗證類型
有許多不同的技術可以用來在用戶訪問遠程服務時對其進行身份驗證,其中包括:
?
集成 Windows 身份驗證。
?
HTTP 基本身份驗證。
?
HTTP 摘要身份驗證。
?
基于證書的身份驗證。
?
基于 Web Services Enhancements (WSE) 的身份驗證。
?
自定義身份驗證。
集成 Windows 身份驗證
對于集成 Windows 身份驗證,用戶是通過使用有效的 Windows 帳戶登錄到他的或她的計算機來進行身份驗證的。憑據(jù)可以是本地帳戶(對于計算機來說,帳戶是本地的)或域帳戶(Windows 域的有效成員)。在用戶的整個會話期間,應用程序都可以透明地使用登錄時所建立的標識來訪問資源。這意味著應用程序可以用一種安全的方式提供對網(wǎng)絡資源(例如 Web 服務)的無縫訪問,而不必提示用戶輸入其他憑據(jù)或重復輸入憑據(jù)。
注只有當網(wǎng)絡資源也使用集成 Windows 身份驗證時,對網(wǎng)絡資源的訪問才是無縫的。
集成 Windows 身份驗證使用以下兩種身份驗證協(xié)議中的一種:Kerberos 或 NTLM。這兩種技術都不通過網(wǎng)絡傳送用戶名和密碼組合來對用戶進行身份驗證或驗證。因此,您的應用程序或基礎結構在傳輸?shù)倪^程中不必提供附加的安全性來管理憑據(jù)。
依賴于 Windows 安全性的客戶端應用程序使用名為 WindowsIdentity 的 IIdentity 接口的實現(xiàn)。
注.NET Framework 也提供緊密相關的 IPrincipal 接口。有關 IIdentity 和 IPrincipal 接口的更多詳細信息,請參閱本章后面的“授權”。
使用集成 Windows 身份驗證的 Web 服務
對于為集成 Windows 身份驗證配置的 Web 服務,客戶端應用程序可以在調(diào)用 Web 服務之前提供當前登錄的用戶的憑據(jù)來進行身份驗證。當從 Microsoft Visual Studio .NET 開發(fā)系統(tǒng)將引用添加到應用程序中的 Web 服務時,系統(tǒng)會自動生成一個代理類并將其添加到項目中,以便通過編程方式訪問 Web 服務。下面的代碼演示了如何設置當前登錄的用戶的用戶憑據(jù)。
MyService service = new MyService(); // A proxy for a web service. service.Credentials = CredentialCache.DefaultCredentials; service.SomeServiceMethod(); // Call the web service.
在本例中,DefaultCredentials 使用應用程序正在其中運行的安全性上下文,它通常是運行應用程序的用戶的 Windows 憑據(jù)(用戶名、密碼和域)。
HTTP 基本身份驗證
HTTP 基本身份驗證是由 IIS 提供的。在進行基本身份驗證時,IIS 會提示用戶輸入一個有效的 Windows 帳戶和密碼。這一組合是作為經(jīng)過編碼的明文從客戶端傳送到服務器,并用于在 Web 服務器上對用戶進行身份驗證。
注為了保護基本身份驗證,您需要保護客戶端和服務器之間的通信信道(例如,通過啟用服務器上的安全套接字層 [SSL]),以確保用戶名/密碼組合被加密并且在傳輸時不會被篡改或截獲。同時,您還需要保護位于服務器上的密碼。然而,SSL 只能保護兩個已定義的終結點之間的通信。如果您需要保護兩個以上的終結點之間的通信,則需要使用基于消息的安全性。
使用基本身份驗證的 Web 服務
對于與為基本身份驗證配置的 Web 服務交互的客戶端應用程序,客戶端可以使用登錄對話框來接受有效的用戶憑據(jù),并用它來進行身份驗證。下面的代碼演示了如何為需要基本身份驗證的 Web 服務代理設置用戶憑據(jù)。
CredentialCache cache = new CredentialCache(); cache.Add( new Uri( service.Url ), // Web service URL. "Basic", // Basic Authentication. new NetworkCredential( userName, password, domain ) ); service.Credentials = cache;
在本例中,userName、password 和 domain 是作為登錄對話框的一部分被接受的。
HTTP 摘要身份驗證
HTTP 摘要身份驗證提供與 HTTP 基本身份驗證相同的功能,但是采用不同的方式來傳輸身份驗證憑據(jù)。身份驗證憑據(jù)是在一種稱為哈希 的單向處理中進行轉換的。這種處理的結果稱為哈希 或 消息摘要,使用當前的技術不可能對其進行解密。
摘要身份驗證按照以下過程進行:
1.
服務器給瀏覽器發(fā)送將在身份驗證過程中使用的特定信息。
2.
瀏覽器將此信息以及一些其他信息添加到它的用戶名和密碼中,然后對其進行哈希運算。附加信息有助于防止有人復制哈希值并再次使用它。
3.
得到的哈希連同附加信息以明文的方式通過網(wǎng)絡發(fā)送到服務器。
4.
服務器將附加信息添加到它所擁有的客戶端密碼的明文副本中,并對所有的信息進行哈希。
5.
服務器將它接收到的哈希值與它剛產(chǎn)生的哈希值進行比較。
6.
只有當兩個值相同時才授予訪問權限。
附加信息是在哈希之前添加到密碼中的,這樣就沒有人可以捕獲密碼哈希并利用它來冒充真實客戶端。幫助標識客戶端、客戶端計算機和客戶端所屬的領域或域的值也被添加到密碼中。同時添加的還有時間戳,以防止客戶端在密碼被撤消后還使用密碼。
因為摘要身份驗證以哈希形式通過網(wǎng)絡發(fā)送密碼,所以它明顯優(yōu)于基本身份驗證,特別是在使用基本身份驗證而沒有對通信信道進行加密時。因此,如果可能,您應該使用摘要身份驗證來代替基本身份驗證。
注如同基本身份驗證的情況一樣,只有在向其發(fā)出請求的域服務器有請求用戶的密碼的明文副本時,摘要身份驗證才完成。因為域控制器有密碼的明文副本,所以您必須確保該服務器是安全的,不會受到物理和網(wǎng)絡攻擊。
基于證書的身份驗證
通過使用證書,客戶端和服務器應用程序可以使用計算機上安裝的數(shù)字密鑰相互進行身份驗證,或建立安全連接。客戶端應用程序可以使用客戶端證書來向服務器標識自己,同樣,服務器也可以使用服務器證書來向客戶端標識自己。一個雙方都信任的第三方(稱為證書頒發(fā)機構)可以確認這些證書的標識??蛻舳俗C書可以映射到 Microsoft Active Directory? 目錄服務中的 Microsoft Windows 帳戶。
您可以建立一個站點,使沒有證書的用戶以來賓身份登錄,而有證書的用戶以他的或她的證書所映射的用戶的身份登錄。然后,您可以基于該證書自定義站點。
如果您需要對單個用戶進行身份驗證,您可以使用一種稱為“一對一映射”的技術,這種技術會將證書映射到單個帳戶。如果您需要對來自特定組或組織的所有用戶進行身份驗證,您可以使用多對一映射,例如,它可以將包含共同的公司名稱的所有證書映射到單個帳戶。
在基于證書的身份驗證中,客戶端應用程序使用的是可以由 Web 服務進行身份驗證的證書。在這種情況中,客戶端應用程序使用 X.509 證書來對 SOAP 消息進行數(shù)字簽名,以確保消息來自受信任的來源,并且在到達指定的 Web 服務之前沒有在傳輸?shù)倪^程中被篡改。
基于證書的身份驗證的一個主要考慮事項是如何處理證書將不再有效的情況。例如,如果一個雇員使用證書來進行身份驗證,之后該雇員被解雇了,則此證書應該不再允許該用戶訪問資源。因此,證書安全性基礎結構包括對證書撤消列表的管理非常重要。這些列表放在服務器上,每當客戶端連接到網(wǎng)絡資源時都將進行檢查。
當智能客戶端脫機工作時,不能對基于服務器的撤消列表進行檢查,因此一個不能訪問服務器上的資源的用戶有可能對客戶端上的資源進行本地訪問。為了幫助解決這個問題,您可以選擇相對短的客戶端證書租約時間。短的租約時間會強制客戶端定期連接到證書服務器,并且在續(xù)訂租約和允許連接到服務器端應用程序之前確認證書尚未撤消。
有關詳細信息,請參閱
http://www.microsoft.com/resources/documentation/windowsserv/2003/standard/proddocs/en-us/sec_auth_certabout.asp 上的“About Certificates”。
基于 WSE 的身份驗證
使用 Web Services Enhancements 版本 2.0,可以通過編程方式簽署 Web 服務的 SOAP 消息。WSE 2.0 是一個實現(xiàn),它支持各種新興的 Web 服務標準,例如 WS-Security、WS-SecureConversation、WS-Trust、WS-Policy、WS-Addressing、WS-Referral、WS-Attachments 和 Direct Internet Message Encapsulation (DIME)。WSE 提供一種編程模型來實現(xiàn)它所支持的各種規(guī)范。
使用 WSE 的客戶端應用程序可以使用 X509CertificateStore 類中的某種 Find 方法(例如 FindCertificateByHash 或 FindCertificateByKeyIdentifier)通過編程方式從存儲區(qū)中選擇一個證書,使用該證書創(chuàng)建數(shù)字簽名,將其添加到 WS-Security SOAP 頭并調(diào)用 Web 服務。另外,客戶端應用程序還可以選擇打開當前登錄用戶的證書存儲區(qū),如下面的代碼示例所示。
X509CertificateStore store; store = X509CertificateStore.CurrentUserStore( X509CertificateStore.MyStore ); bool open = store.OpenRead();
有關詳細信息,請參閱
http://msdn.microsoft.com/webservices/building/wse/default.aspx 上的“Web Services Enhancements”。
有關使用客戶端證書的詳細信息,請參閱 WSE 2.0 文檔中的“Signing a SOAP Message Using an X.509 Certificate”。
自定義身份驗證
在某些情況下,Windows 提供的標準身份驗證選擇并不適用于您的應用程序,您將可能需要設計您自己的身份驗證形式。幸運的是,.NET Framework 提供了一些選擇來幫助您設計自定義身份驗證解決方案。
.NET Framework 支持 IIdentity 的一個實現(xiàn),稱為 GenericIdentity。您可以使用 GenericIdentity,也可以創(chuàng)建您自己的自定義標識類。設計自定義身份驗證解決方案可能比較困難,因為您必須自己采取措施來確保方法是安全的。您可能還需要為您的標識維護單獨的存儲區(qū)。
收集和驗證用戶憑據(jù)
不管您使用的是什么形式的身份驗證,您都需要收集用戶憑據(jù),然后可以對其進行驗證。對于已經(jīng)使用集成 Windows 身份驗證登錄的用戶,您可能只需收集現(xiàn)有的憑據(jù),而對于自定義身份驗證解決方案,您可能需要通過您自己的登錄對話框來安全地收集憑據(jù)。
注不要將用戶憑據(jù)存儲在代碼中超過必要的時間。特別是,不要用全局變量存儲憑據(jù),它們是通過可公開訪問的方法或屬性提供訪問的,另外,也不要將憑據(jù)保存在磁盤上。
收集當前登錄的用戶的憑據(jù)
如果您使用的是集成 Windows 身份驗證,則您的用戶是在他們的 Windows 會話開始時登錄的。然后,您的應用程序可以使用這一信息來確保他們具有適當?shù)膽{據(jù)用于運行。
下面的代碼演示了基本功能。
using System.Security.Principal; // Get principal of the currently logged in user. WindowsPrincipal wp = new WindowsPrincipal( WindowsIdentity.GetCurrent() ); // Display the current user name. label1.Text = "User:" + wp.Identity.Name; // Determine if user is part of a windows group. if( wp.IsInRole( "YourDomain\\YourWindowsGroup" ) ) { // Is a member. } else { // Is not a member. } 使用登錄對話框收集用戶憑據(jù)
如果您設計您自己的登錄對話框接受來自用戶的憑據(jù),則需要采取大量的措施來確保您滿足您的組織的安全性要求(例如強制執(zhí)行強密碼策略和在定期的時間間隔內(nèi)讓密碼過期)。在設計登錄對話框時,請考慮使用下列指導原則:
?
不要盲目信任用戶輸入。如果您盲目信任用戶輸入,惡意用戶就可能危及您的應用程序的安全。例如,如果不對動態(tài)構造 SQL 代碼進行驗證,使用輸入的應用程序就容易受到 SQL 插入攻擊。
?
檢查輸入數(shù)據(jù)的類型、格式或范圍??紤]使用正則表達式來進行這些檢查。使用正則表達式可以檢查類型(例如,字符串或整型)、格式(例如,強制密碼策略要求使用諸如數(shù)字、特殊符號及大小寫字母字符混合等)和范圍(例如,用戶名稱最少包含 6 個字符,最多包含 25 個字符)。
下面的代碼示例強制要求密碼長度為 8 至 10 個字符,并且是大小寫字母和數(shù)字字符的組合。
// Validate the user supplied password. if( !Regex.Match( textBox1.Text, @"^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$", RegexOptions.None ).Success ) { // Invalid email address. }
?
在設計帶有密碼字段文本框的對話框時,請確保 PasswordChar 屬性設置為當文本輸入控件時顯示的字符,如下面的示例所示。
// The password character is set to asterisk. textBox1.PasswordChar = ?*‘;
身份驗證指導原則
在為應用程序設計身份驗證時,應該考慮使用下列指導原則:
?
確定在用戶與應用程序交互時什么階段需要進行身份驗證。
?
考慮在用戶登錄到客戶端時使用集成 Windows 身份驗證對他們進行身份驗證,之后用戶就可以訪問應用程序、應用程序的數(shù)據(jù)和任何遠程服務。
?
如果應用程序是集中部署的并且需要將訪問僅限于經(jīng)過授權的用戶,就應該在應用程序運行時使用 IIS 提供的身份驗證機制之一對用戶進行身份驗證。
?
如果應用程序提供敏感功能或者提供對本地保存的敏感數(shù)據(jù)的訪問,則應該確保在允許用戶訪問之前對他們進行適當?shù)纳矸蒡炞C。
?
如果應用程序需要自定義身份驗證,則應該確保應用程序強制執(zhí)行強用戶名和密碼策略。作為慣例,應該需要最少 8 個字符和大小寫字母字符、數(shù)字和特殊字符的混合。
?
如果遠程服務提供敏感功能或者提供對敏感數(shù)據(jù)的訪問,則需要對用戶進行身份驗證,以便他們通過網(wǎng)絡訪問遠程服務。
?
確保用戶憑據(jù)在沒有保護措施的情況下不通過網(wǎng)絡進行傳輸。有些身份驗證形式根本不通過網(wǎng)絡傳送用戶憑據(jù),但是如果必須傳送,就應該確保它們經(jīng)過加密,或者通過安全連接進行傳送。
有關詳細信息,請參閱 Improving Web Application Security: Threats and Countermeasures 的“Chapter 4 — Design Guidelines for Secure Web Applications”中的“身份驗證”,地址在
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/THCMCh04.asp。
返回頁首授權
在對用戶進行身份驗證之后,可以通過授權來確定他們有權訪問系統(tǒng)內(nèi)的什么內(nèi)容。授權是確認經(jīng)過身份驗證的用戶具有執(zhí)行某種操作的權限的過程。授權管理經(jīng)過身份驗證的用戶可以訪問的資源(例如,文件和數(shù)據(jù)庫)和可以執(zhí)行的操作(例如,更改密碼或刪除文件)。沒有經(jīng)過身份驗證的用戶(即匿名用戶)不能進行特別授權,而是需要分配一組默認權限。
許多因素嚴格地確定了您可以如何在您的環(huán)境中執(zhí)行授權。您需要確定是基于應用程序的功能還是基于系統(tǒng)資源來管理授權。您需要確定是執(zhí)行方法內(nèi)的細粒度授權還是執(zhí)行方法級的檢查。此外,您還需要確定在何處存儲授權所需的用戶信息(例如,在 Active Directory 或 Microsoft SQL Server 數(shù)據(jù)庫中)。如果您將允許您的智能客戶端能夠脫機工作,則需要有對脫機客戶端進行授權的策略。
.NET Framework 提供 IPrincipal 接口,它可以與 IIdentity 接口一起,用于定義管理運行代碼的安全上下文的屬性和方法。同時提供的還有該接口的兩個實現(xiàn):WindowsPrincipal 和 GenericPrincipal。使用集成 Windows 身份驗證的客戶端應用程序使用的是 WindowsPrincipal,而使用自定義身份驗證的客戶端應用程序使用的是 GenericPrincipal。
授權的類型
Windows 操作系統(tǒng)中常用的授權方法有兩種:基于資源的授權和基于角色的授權?;谫Y源的授權依賴于訪問控制列表 (ACL),而基于角色的授權則基于用戶角色執(zhí)行授權。
基于資源的授權
對于基于資源的授權,可以將任意訪問控制列表 (DACL) 附加到保險對象。然后,系統(tǒng)作出訪問決定,方法是比較令牌中的組成員身份與 ACL 的內(nèi)容,以確定該用戶是否具有所請求的訪問權限。對于許多類型的應用程序,ACL 模型是非常理想的。然而,它并非適合于所有的情況。例如,您可能需要基于業(yè)務邏輯或者基于在需要時創(chuàng)建的非持久性對象來作出訪問決定。
基于角色的授權
基于角色的授權允許您將用戶和組與他們完成其工作所需的權限相關聯(lián)。當將一個用戶或組添加到一個角色中時,該用戶或組就會自動地繼承各種安全權限。這些權限可以是執(zhí)行操作的權限,也可以是訪問各種資源的權限。圖 5.1 說明了基于角色的授權中角色與權限之間的關系。
圖 5.1 基于角色的授權
在 Microsoft Windows 2000 Server Service Pack 4 (SP4) 和 Windows Server 2003 操作系統(tǒng)中,基于角色的授權通常是通過授權管理器管理的。授權管理器是一組基于 COM 的運行時接口、以及用于配置的 Microsoft 管理控制臺 (MMC) 管理單元。開發(fā)人員可以使用授權管理器確保應用程序能夠管理和驗證客戶端對執(zhí)行應用程序操作的請求,而應用程序管理員則可以用它來管理用戶角色和權限。通過使用授權管理器,可以將低級操作聚集成稱為“Tasks”的組,并管理這一級別的授權。同時它還使得您能夠在授權前后運行自定義授權邏輯。
授權管理器的一個顯著優(yōu)點是,它可以從需要授權的應用程序中進一步抽象授權存儲,這意味著開發(fā)人員可以一直與授權管理器通信,而不管存儲是在 Active Directory 中還是基于文件的。
給應用程序添加授權功能
.NET Framework 提供了許多選擇來給應用程序添加授權功能。這些選擇包括:
?
使用 PrincipalPermissionAttribute 執(zhí)行聲明性 Demand。
?
使用 PrincipalPermission 對象執(zhí)行命令性 Demand。
?
使用 IsInRole 方法執(zhí)行角色檢查。
?
執(zhí)行用于自定義身份驗證的角色檢查。
使用 PrincipalPermissionAttribute 執(zhí)行聲明性 Demand
可以將 Demand 放在類級或成員級的單個方法、屬性或事件上。如果將聲明性 Demand 同時放在類級和成員級上,則成員級的聲明性 Demand 會重寫(或替換)類級的 Demand。
下面的代碼示例顯示了 PrincipalPermission 對象的聲明性 Demand。
// Declarative example. [PrincipalPermissionAttribute( SecurityAction.Demand, Role="Teller" )] void SomeTellerOnlyMethod() { } 使用 PrincipalPermission 對象執(zhí)行命令性 Demand
可以執(zhí)行命令性 Demand,方法是通過編程方式調(diào)用 PrincipalPermission 對象的 Demand 方法,如下面的代碼示例所示。
// Programmatic example. public SomeMethod() { PrincipalPermission permCheck = new PrincipalPermission( null, "Teller" ); permCheck.Demand(); // Only Tellers can execute the following code. // Non members of the Teller role result in a security exception. . . . }
通過編程方式調(diào)用該方法的一個優(yōu)點是,可以確定主體是否在多個角色中。.NET Framework 不允許以聲明的方式這樣做。下面的代碼示例顯示了如何執(zhí)行這一檢查。
// Using PrincipalPermission. PrincipalPermission permCheckTellers = new PrincipalPermission( null, "Teller" ); permCheckTellers.Demand(); PrincipalPermission permCheckMgr = new PrincipalPermission( null, "Manager" ); permCheckMgr.Demand(); 使用 IsInRole 方法執(zhí)行角色檢查
可以選擇直接訪問主體對象的值并執(zhí)行檢查,而不使用 PrincipalPermission 對象。在這種情況下,可以讀取當前線程的主體的值,也可以使用 IsInRole 方法來執(zhí)行授權,如下面的代碼示例所示。
// Using IsInRole. if ( Thread.CurrentPrincipal.IsInRole( "Teller" ) && Thread.CurrentPrincipal.IsInRole( "Manager" ) ) { // Perform privileged operation. } 執(zhí)行用于自定義身份驗證的角色檢查
如果應用程序不是基于 Windows 的,則可以通過編程方式將一組從自定義身份驗證數(shù)據(jù)存儲區(qū)(例如 SQL Server 數(shù)據(jù)庫)中獲得的角色填充 GenericPrincipal 對象,如下面的代碼示例所示。
GenericIdentity userIdentity = new GenericIdentity( "Bob" ); // Typically role names would be retrieved from a custom data store. string[] roles = new String[]{ "Manager", "Teller" }; GenericPrincipal userPrincipal = new GenericPrincipal( userIdentity, roles ); if ( userPrincipal.IsInRole( "Teller" ) ) { // Perform privileged operation. } 授權指導原則
授權對控制用戶訪問應用程序功能和資源的權限非常關鍵。不適當?shù)幕蛉醯氖跈鄷е滦畔⑿孤逗蛿?shù)據(jù)篡改。請考慮使用下列指導原則:
?
盡可能地使用多個網(wǎng)關守衛(wèi)以在用戶訪問資源或執(zhí)行操作時強制執(zhí)行授權檢查。使用客戶端檢查和服務器上的檢查相結合的方法來提供深層防御,以防止設法繞開其中一個網(wǎng)關守衛(wèi)的惡意用戶的攻擊。服務器上常見的網(wǎng)關守衛(wèi)包括 IIS Web 權限、NTFS 文件系統(tǒng)權限、Web 服務文件授權(只適用于 Windows 身份驗證)和主體權限 Demand。
?
使用用戶的安全上下文授權訪問系統(tǒng)資源??梢允褂没诮巧氖跈鄟砘谟脩魳俗R和角色成員身份授權訪問。集成 Windows 身份驗證與安全資源(例如文件或注冊表)上的 Windows ACL 共同確定是否允許調(diào)用者訪問資源。對于程序集,可以基于諸如程序集的強名稱或位置等證據(jù)來授權調(diào)用代碼。
?
確保使用足夠的粒度來定義角色,以便充分分離特權。避免只為滿足某些用戶的要求而授予提高的特權;相反,考慮添加新的角色來滿足這些要求。
?
盡可能地使用聲明性 Demand 而非命令性 Demand。聲明性 Demand 提供或拒絕對方法的全部功能的訪問。另外,它們還可以更好地與安全工具一起使用,并且有助于進行安全審核,因為這些工具能夠通過檢驗應用程序來訪問這些 Demand。
?
如果您需要確定主體是否在多個角色中,則可以考慮使用 IsInRole 方法進行命令性檢查。.NET Framework 版本 1.1 不允許以聲明的方式執(zhí)行 AND 檢查;然而,可以通過編程的方式在方法內(nèi)執(zhí)行它們,如下面的代碼示例所示。
// Checking for multiple roles. if ( Thread.CurrentPrincipal.IsInRole( "Teller" ) && Thread.CurrentPrincipal.IsInRole( "Manager" ) ) { // Perform privileged operation. }
?
使用代碼訪問安全來授權調(diào)用對特權資源或操作的代碼訪問(基于諸如程序集的強名稱或位置這樣的證據(jù))。有關詳細信息,請參閱本章后面的“代碼訪問安全”。
客戶端脫機時授權使用功能
當用戶連接到網(wǎng)絡時,可以直接根據(jù)網(wǎng)絡授權存儲對他們進行授權;但是當他們沒有連接到網(wǎng)絡時,仍然可能需要對他們進行授權。
任何形式的授權都不會比所使用的身份驗證機制更強。如果您允許匿名身份驗證,您就應該特別注意允許用戶訪問什么功能,并且通常不應該授權用戶訪問系統(tǒng)資源。
如果您授權用戶使用應用程序,則可以讓 Windows 擔當唯一的網(wǎng)關守衛(wèi)來確定哪些資源可用于已登錄用戶的配置文件。在這種情況下,通常只允許用戶訪問本地系統(tǒng)資源。
您可以選擇為不同的角色創(chuàng)建同一個應用程序的不同版本。當用戶連接到網(wǎng)絡時,他或她只被允許安裝與其角色相符的應用程序版本。然后,當用戶脫機運行應用程序時,無需為應用程序建立連接即可自動提供正確的功能。
授權和配置文件應用程序塊
Microsoft 提供了一個應用程序塊,它能夠提供基礎結構來簡化在應用程序中加入授權功能的過程。
授權和配置文件應用程序塊為基于角色的授權和對配置文件信息的訪問提供基礎結構。該應用程序塊允許您執(zhí)行下列操作:
?
對應用程序或系統(tǒng)的用戶進行授權。
?
使用多個授權存儲提供程序。
?
插入操作驗證的業(yè)務規(guī)則。
?
將多個標識映射到單個用戶,從而將標識的概念擴展到包括身份驗證方式。
?
訪問可以存儲在多個配置文件存儲區(qū)中的配置文件信息。
有關詳細信息,請參閱
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/authpro.asp 上的 Authorization and Profile Application Block。
返回頁首輸入驗證
輸入驗證不嚴格的應用程序可能會受到攻擊者惡意輸入的威脅。驗證用戶輸入是保護應用程序的最前沿防線中的一道防線。請考慮使用下面針對智能客戶端應用程序的輸入驗證指導原則:
?
確保智能客戶端應用程序在處理輸入或將輸入傳送到下游資源和程序集之前驗證了所有的輸入。
?
如果您要將輸入數(shù)據(jù)傳送給非托管 API,請對用戶輸入數(shù)據(jù)進行徹底的驗證。這樣做有助于防止緩沖區(qū)溢出。您還應該限制用戶輸入傳送到非托管 API 的數(shù)據(jù)。
?
始終驗證從所有外部來源(例如 Web 站點和 Web 服務)獲得的數(shù)據(jù)。
?
切勿依賴對傳送到 Web 服務器或者 Web 應用程序的數(shù)據(jù)進行的客戶端驗證。首先在客戶端驗證數(shù)據(jù),然后再次在服務器上驗證數(shù)據(jù),以便防止繞過客戶端驗證的惡意輸入。
?
切勿允許用戶直接輸入 SQL 查詢。始終提供針對安全問題進行了徹底的檢查的預先打包的或參數(shù)化查詢。允許用戶直接輸入 SQL 查詢可能帶來 SQL 插入攻擊。
?
用已知的正確值或模式(而不是用錯誤的輸入)來約束并驗證用戶輸入。檢查一個有限已知值的列表比檢查一個無限未知惡意輸入類型的列表簡單得多。在對輸入值采取行動之前,既可以拒絕有害的輸入,也可以對輸入進行凈化(即除去潛在的不安全字符)。
?
通過驗證輸入的類型、長度、格式和范圍來約束它。一種這樣做的方法就是使用正則表達式(可以從 System.Text.RegularExpressions 命名空間中獲得)來驗證用戶輸入。
?
拒絕未知的有害數(shù)據(jù),然后凈化輸入。如果應用程序需要接受某些自由格式的用戶輸入(例如,文本框中的注釋),可以對輸入進行凈化,如下面的示例所示:
private string SanitizeInput( string input ) { // Example list of characters to remove from input. Regex badCharReplace = new Regex( @"([<>""?%;()&])" ); string goodChars = badCharReplace.Replace( input, "" ); return goodChars; }
?
考慮集中驗證例程,以減少開發(fā)工作量并有助于未來的維護。
有關詳細信息,請參閱 Improving Web Application Security: Threats and Countermeasures 的“Chapter 4 — Design Guidelines for Secure Web Applications”中的“輸入驗證”,地址在
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/THCMCh04.asp。
返回頁首處理敏感數(shù)據(jù)
如果您經(jīng)常設計 Web 應用程序,您就會理解保護存儲的數(shù)據(jù)和傳輸?shù)臄?shù)據(jù)的重要性。存儲在 Web 服務器上的數(shù)據(jù)通常被寫入物理上安全的位置,這樣的位置已經(jīng)很好地被保護起來以防止受到攻擊。在智能客戶端應用程序中,您同樣需要仔細考慮駐留在客戶端上的數(shù)據(jù)。如果這些數(shù)據(jù)是敏感的,適當?shù)貙ζ溥M行處理以確保安全就非常重要。為了保護傳輸?shù)臄?shù)據(jù),您可以使用 SSL 保護傳輸層,并且使用 WS-Security 或 Message Queuing 加密工具保護消息內(nèi)容。
只有授權用戶訪問的數(shù)據(jù)才應該可用于客戶端應用程序。如果一臺計算機上的多個人都可以使用客戶端應用程序,則與每個單獨的用戶相關的數(shù)據(jù)都應該被認為是敏感數(shù)據(jù),并且應該采取一些措施來確保只有經(jīng)過授權的用戶可以訪問它。
敏感數(shù)據(jù)包括攻擊者可能發(fā)現(xiàn)對訪問或修改有用的任何數(shù)據(jù),因為這些信息是機密的或者對攻擊有幫助。敏感數(shù)據(jù)可以是服務器提供給客戶端的數(shù)據(jù),但也可以包括應用程序配置文件、本地數(shù)據(jù)庫或注冊表信息。
在通常情況下,應該盡力確保敏感數(shù)據(jù)不本地緩存。然而,在智能客戶端應用程序的情況下,可能需要緩存這些數(shù)據(jù)(例如,為允許偶爾連接的操作,將數(shù)據(jù)保存在本地存儲區(qū)以供日后使用)。
注在某些情況下,敏感數(shù)據(jù)可能由于內(nèi)存中的分頁而發(fā)送到磁盤上。因此,在確定需要對什么樣的數(shù)據(jù)進行加密時,也應該考慮存在于內(nèi)存中的數(shù)據(jù)。
確定將哪些數(shù)據(jù)存儲在客戶端上
根據(jù)定義,用戶(因而是潛在的攻擊者)可以在物理上接觸客戶端。如果給予足夠的時間,攻擊者常常能夠獲得足夠的管理權限來訪問幾乎任何數(shù)據(jù),因此您應該仔細考慮應該將什么樣的數(shù)據(jù)存放在客戶端。作為一般的規(guī)則,您應該對服務器進行授權決策,這樣,就只有您從服務器傳送到客戶端的數(shù)據(jù)是允許用戶訪問的數(shù)據(jù)。除了提高性能之外,對服務器進行授權決策也可以確保這種數(shù)據(jù)不會被客戶端上的潛在攻擊者訪問得到。
您應該從不將敏感數(shù)據(jù)存儲在基于文本的文件中,并且應該始終對這些數(shù)據(jù)進行加密,這樣就只有經(jīng)過授權的用戶才可以輕松地進行訪問。您應該避免使用基于文本的配置文件來存儲敏感的安全信息,例如密碼或數(shù)據(jù)庫連接字符串。如果這些信息必須在本地存儲,您就應該對信息進行加密,并將其存儲在文件或注冊表項中,然后使用 DACL 來限制對該對象的訪問。此外,還必須保護針對登錄用戶個人的任何永久性數(shù)據(jù)的隱私和安全,特別是當計算機在用戶之間共享時。
在許多情況下,如果應用程序需要脫機運行,則較多的數(shù)據(jù)就會存儲在客戶端上。然而,您應該確定脫機時是否需要所有的數(shù)據(jù),或者是否您想要限制用戶在脫機時執(zhí)行某些操作,這樣您就不必將敏感數(shù)據(jù)緩存在本地。
在某些情況下,如果數(shù)據(jù)是機密的,并且可以按需要由用戶輸入,則可以選擇根本不將數(shù)據(jù)本地存儲在客戶端上,而是在需要時從用戶獲得。
如果應用程序需要在本地存儲敏感數(shù)據(jù),通常應該避免使用可移動存儲器(例如軟盤、zip 磁盤、或 USB 存儲設備)或外部便攜式存儲器來存儲敏感數(shù)據(jù)。然而,當可以確保可移動媒體為該用戶所有(例如,通過使用證書或智能卡)時,就可以將特定于用戶的數(shù)據(jù)存儲在可移動媒體中。因此,可以將特定于用戶的數(shù)據(jù)存放在隨用戶一起移動的安全位置,這樣,漫游用戶就可以在不將數(shù)據(jù)保留在本地計算機上的情況下訪問應用程序及其數(shù)據(jù)。
注當考慮將哪些敏感數(shù)據(jù)存儲在客戶端上時,您應該確保存儲關于雇員或顧客的信息沒有違反隱私法規(guī)。這些法律因國家/地區(qū)而異,因此您應該熟悉使用您的應用程序的國家/地區(qū)的隱私法規(guī)。
保護敏感數(shù)據(jù)的技術
對于需要存儲在客戶端上的數(shù)據(jù),有許多可以采取的附加措施來防止未經(jīng)授權的訪問。這些措施包括下列內(nèi)容:
?
確保只有經(jīng)過授權的用戶才可以訪問數(shù)據(jù)。
?
考慮使用 EFS 加密文件。
?
考慮使用 DPAPI 避免密鑰管理問題。
?
考慮存儲哈希值而不是明文。
?
考慮部分受信任的應用程序的隔離存儲。
?
保護私鑰。
確保只有經(jīng)過授權的用戶才可以訪問數(shù)據(jù)
數(shù)據(jù)常常需要進行保護,以幫助確保只有經(jīng)過授權的用戶才可以訪問。取決于應用程序的性質和數(shù)據(jù)保持有效的時間,可以選擇使用基于資源的安全性或基于角色的安全性來保護數(shù)據(jù)。有關詳細信息,請參閱本章前面的“授權指導原則”。
考慮使用 EFS 加密文件
確保將文件安全地存放在智能客戶端上的一種方法是使用加密文件系統(tǒng) (Encrypting File System, EFS) 對敏感數(shù)據(jù)文件進行加密。這個解決方案在可擴展方面乏善可陳;然而,它對某些特定的文件非常有用,它也可以用于在客戶端上本地緩存數(shù)據(jù)的情況(例如,用于啟用偶爾連接的智能客戶端)。
考慮使用 DPAPI 避免密鑰管理問題
Windows 2000 和 Windows 操作系統(tǒng)的更高版本提供了用于加密和解密數(shù)據(jù)的 Win32? 數(shù)據(jù)保護 API (DPAPI)。它是加密 API (Crypto API) 的一部分,并且是用 crypt32.dll 實現(xiàn)的。它包含兩個方法:CryptProtectData 和 CryptUnprotectData。
DPAPI 特別有用,因為它可以消除暴露給使用密碼的應用程序的密鑰管理問題。雖然加密可以確保數(shù)據(jù)是安全的,但是您必須采取額外的步驟來確保密鑰的安全。為了派生加密密鑰,DPAPI 使用與調(diào)用 DPAPI 函數(shù)的代碼相關的用戶帳戶的密碼。因此,是由操作系統(tǒng)(而不是由應用程序)管理密鑰。
DPAPI 可以與機器存儲區(qū)或用戶存儲區(qū)一起工作。用戶存儲區(qū)是基于登錄用戶的配置文件自動加載的??蛻舳藨贸绦蛲ǔEc用戶存儲區(qū)一起使用 DPAPI,除非需要存儲為所有可以登錄到計算機的用戶共有的機密。
DPAPI 用來加密和解密敏感數(shù)據(jù)的密鑰是特定于計算機的。系統(tǒng)會為每臺計算機生成一個不同的密鑰,這可以防止一個服務器能夠訪問由另一個服務器加密的數(shù)據(jù)。
非托管 DPAPI 需要程序集具有完全的信任。具有完全和部分受信任的程序集的應用程序可以使用高特權來分離代碼,并且使其能夠從部分受信任的代碼中進行調(diào)用。有關更多信息,請參閱
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secmod/html/secmod115.asp 上的“How To Create a Custom Encryption Permission”。
考慮存儲哈希值而不是明文
有時,存儲數(shù)據(jù)是為了使之可以用于驗證用戶輸入(例如,用戶名和密碼的組合)。在這樣的情況下,可以存儲數(shù)據(jù)的加密哈希,而不是以明文的形式存儲數(shù)據(jù)本身。然后,當用戶進行輸入時,還可以對該數(shù)據(jù)進行哈希運算,并且可以比較兩個哈希。存儲哈希減少了機密被發(fā)現(xiàn)的風險,因為從其哈希推導原始數(shù)據(jù)或從其他數(shù)據(jù)生成相同的哈希在計算上是不可能的。
考慮部分受信任的應用程序的隔離存儲
隔離存儲允許應用程序將數(shù)據(jù)保存到唯一的數(shù)據(jù)艙,數(shù)據(jù)艙與代碼的標識的某些方面相關聯(lián),例如它的 Web 站點、發(fā)布者或簽名。數(shù)據(jù)艙是一個抽象的概念,而不是一個具體的存儲位置;它由一個或多個隔離的存儲文件(稱為存儲)組成,存儲包含存儲數(shù)據(jù)的實際目錄位置。
對于需要存儲特定于特定用戶和程序集的狀態(tài)數(shù)據(jù)的部分受信任的應用程序,隔離存儲特別有用。部分受信任的應用程序并不直接訪問文件系統(tǒng)來保持狀態(tài),除非通過更改安全策略顯式地授予它們這樣做的權限。
存儲在隔離存儲中的數(shù)據(jù)是隔離的,并且受到保護,不會被其他部分受信任的應用程序訪問,但是無法保護它不會被完全受信任的代碼或有權訪問客戶端計算機的其他用戶訪問。為了在這些情況下保護數(shù)據(jù),您應該通過使用 DACL 采用數(shù)據(jù)加密或者文件系統(tǒng)安全性。有關詳細信息,請參閱
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconIntroductionToIsolatedStorage.asp 上的 .NET Framework Developer‘s Guide 中的“Introduction to Isolated Storage”。
保護私鑰
未受保護的私鑰易于受到惡意用戶或惡意代碼進行的各種各樣的攻擊。用于簽署程序集的私鑰不應該放在不安全的位置,例如開發(fā)人員的計算機或開放共享的環(huán)境。攻擊者可以使用竊取的私鑰簽署帶有您的強名稱的惡意代碼。您確實應該通過您的組織內(nèi)為此目的而指定的中央安全機構來保護您的私鑰。您也可以將私鑰保存在物理上安全的隔離計算機上,并且在必要時使用便攜式媒體來傳遞密鑰。
有關有效地存儲機密的詳細信息,請參閱 Michael Howard 和 David LeBlanc 撰寫的 Writing Secure Code, Second Edition。
返回頁首代碼訪問安全
代碼訪問安全是 .NET Framework 技術,它將身份驗證和授權原則應用于代碼而不是用戶。代碼訪問安全是一種強大的機制,它確保只有用于運行的代碼才可以被用戶運行。
所有的托管代碼都遵循代碼訪問安全機制。當加載一個程序集時,會授予它一組代碼訪問權限,以確定它可以訪問什么資源和執(zhí)行什么類型的特權操作。為了授予這些權限,.NET Framework 安全系統(tǒng)使用證據(jù)來對代碼進行身份驗證(標識)。
注 程序集是代碼訪問安全的配置和信任單元。相同程序集中的所有代碼都接收相同的權限,因而是同等受信任的。
代碼訪問安全包括下列要素:
?
權限。權限代表代碼訪問安全資源或執(zhí)行特權操作的權力。Microsoft .NET Framework 提供代碼訪問權限 和代碼標識權限。代碼訪問權限封裝訪問特特定資源或者執(zhí)行特定特權操作的能力。例如,在應用程序可以執(zhí)行任何文件的 I/O 操作之前都需要 FileIOPermission。代碼標識權限用來基于調(diào)用代碼的標識的某個方面(例如,代碼的強名稱)限制對代碼的訪問。
?
權限集。.NET Framework 定義了許多權限集,它們代表一組通常作為一個整體分配的權限。例如,.NET Framework 定義的 FullTrust 權限集將所有的權限分配給完全受信任的代碼;而 LocalIntranet 權限集則分配數(shù)量非常有限的權限。
?
證據(jù)。.NET Framework 安全系統(tǒng)使用證據(jù)來標識程序集。代碼訪問安全策略使用證據(jù)來幫助將恰當?shù)臋嘞奘谟枨‘數(shù)某绦蚣?。證據(jù)可以是位置相關的(例如,URL、站點、應用程序目錄或區(qū)域),也可以是作者相關的(例如,強名稱、發(fā)布者或哈希)。
?
策略。代碼訪問安全策略是由管理員配置的,它確定授予程序集的權限。策略可以建立在企業(yè)、機器、用戶和應用程序域級別上。每個策略都用一個 XML 配置文件定義。
?
代碼組。每個策略文件都包含一些分層代碼組。代碼組用來給程序集分配權限。代碼組由成員身份條件(基于證據(jù))和權限集組成。.NET Framework 定義了許多默認的代碼組,例如 Internet、本地 Intranet、受限制的和受信任的區(qū)域。
有關代碼訪問安全的詳細信息,請參閱
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/THCMCh07.asp 上的 Improving Web Application Security: Threats and countermeasures:“Chapter 7 — Building Secure Assemblies”和
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/THCMCh08.asp 上的“Chapter 8 — Code Access Security in Practice”。
代碼訪問安全權限解析
代碼訪問安全使用圖 5.2 中概述的步驟來確定將哪些權限分配給程序集。
圖 5.2 確定將哪些權限分配給程序集
下面的步驟更詳細地描述了這些過程:
1.
加載程序集,收集證據(jù)并將其提供給主機。
2.
根據(jù)用于宿主環(huán)境的安全策略來評估證據(jù)。
3.
這種評估的輸出是一組授予程序集的權限。這些權限定義了在此環(huán)境中程序集能夠做什么和不能做什么。
4.
當程序集請求執(zhí)行特權操作時,系統(tǒng)就會將操作的請求與程序集的權限進行比較。如果程序集具有這樣的權限,就允許代碼執(zhí)行該操作,否則,引發(fā)安全異常。
代碼訪問安全設計
分配給代碼的權限取決于與代碼相關的證據(jù)和客戶端計算機上的適當安全策略。為了在保持應用程序的功能的同時確保其安全,您需要仔細考慮應用程序所需的權限、以及授予這些權限的方式。
授予所有權限的應用程序(這些應用程序定義在 FullTrust 權限集中)稱為完全受信任的應用程序。沒有授予所有權限的應用程序稱為部分受信任的應用程序。
在理論上,將應用程序設計為部分受信任通常更可取。然而,智能客戶端應用程序常常需要執(zhí)行許多部分受信任的應用程序在默認情況下不能執(zhí)行的操作。這些操作包括:
?
訪問運行應用程序的服務器以外的服務器,或者訪問使用不同協(xié)議的服務器。
?
訪問本地文件系統(tǒng)。
?
訪問本地 Microsoft Office 應用程序并與其交互。
?
訪問并與非托管代碼(例如 COM 對象)交互。
如果需要智能客戶端執(zhí)行這些種類的操作,則應該考慮使它成為一個完全受信任的應用程序,或者授予它正確地進行操作所需的其他特定權限。
注在默認情況下,使用無接觸部署方式部署的應用程序自動成為部分受信任的。如果智能客戶端需要執(zhí)行部分受信任的應用程序不能執(zhí)行的額外操作,則需要部署新的安全策略或者使用其他方法來部署應用程序。
設計和構建部分受信任的應用程序可能比較復雜,但是仔細考慮并限制授予應用程序的權限有助于確保應用程序不能執(zhí)行不恰當?shù)牟僮骰蛘咴L問明顯不需要的資源。
所有的代碼在運行之前都必須給其授予運行的權限,但是訪問安全資源或者執(zhí)行其他安全敏感操作(例如調(diào)用非托管代碼或訪問本地文件系統(tǒng))的代碼必須由 .NET Framework 授予額外的權限才能運行。這樣的代碼稱為特權代碼。相反,非特權代碼并不需要訪問敏感資源,而只是需要運行的權限。當設計和構建應用程序及其程序集時,應該標識特權和非特權代碼并將其存檔。這樣做有助于確定代碼需要的權限。
還應該仔細檢驗 .NET Framework 使用哪些證據(jù)來給代碼分配權限。只有在中心位置安全的情況下才應該考慮基于應用程序的位置(例如,文件共享或 Web 服務器)的證據(jù)。類似地,只有在密鑰安全的情況下才應該使用具有基于一般密鑰 — 用于簽署所有的代碼(例如,由組織的 IT 部門)— 的證據(jù)的應用程序。然而,依賴于強名稱證據(jù)而不是任何基于位置的證據(jù)(例如 Web 服務器地址)通常更安全一些。
設計部分受信任的應用程序
當設計部分受信任的應用程序時,請遵循下列指導原則:
?
了解應用程序的部署方案。
?
避免引起異常的權限請求。
?
對部分受信任的調(diào)用程序使用 Demand/Assert 模式。
?
考慮對程序集使用強名稱。
?
避免給受限區(qū)域賦予完全的信任。
了解應用程序的部署方案
在設計期間應該清楚地了解應用程序的部署方案,因為部署應用程序的位置對默認授予應用程序的權限有很大的影響。諸如顯示對話框(例如,使用 SaveFileDialog)或訪問系統(tǒng)資源的應用程序功能都可能因為應用程序的部署位置而受到限制。
特別地,授予應用程序的權限取決于它所在的區(qū)域(例如,Internet 區(qū)域、本地 Intranet 區(qū)域或受信任的區(qū)域)。用戶可以對受信任的區(qū)域內(nèi)的應用程序的成員身份有一定的控制,但是不應該依賴用戶將應用程序放在此區(qū)域來確保正確的功能。您應該這樣設計您的應用程序,使之在運行時被授予的權限不夠時會正常地失敗。
如果用戶嘗試執(zhí)行某種操作,而應用程序卻沒有足夠的權限來執(zhí)行該操作,則這種嘗試可能會導致失敗的權限請求,這又會引發(fā)安全異常。應用程序需要處理這些異常,否則它就會出現(xiàn)故障。您應該確??梢院芎玫靥幚磉@樣的故障,并且應該給用戶提供足夠的信息來解決問題,而同時不泄露與安全有關的不適當?shù)幕蛎舾械男畔ⅰ?div style="height:15px;">
注系統(tǒng)可以按照使用 .NET Framework 2.0 版本的 ClickOnce 部署功能部署的應用程序的部署清單授予它們特定的權限。在部署應用程序時,授予的權限將固定,而且將應用程序的位置放在受信任的區(qū)域中不會影響授予的權限。
設計一個替代解決方案來避免可能引起異常的權限請求。例如,對于基于 Intranet 的應用程序,您可以使用 OpenFileDialog 來顯示一個對話框,指示用戶選擇文件,而不要讓應用程序自動從硬盤打開并讀取文件。
適當?shù)靥幚懋惓5臋z查權限(特別是 SecurityException)。在您的代碼中,您可以創(chuàng)建一個特定于您正試圖訪問的資源的權限類的實例,并且在訪問資源之前檢查必要的權限。例如,當您必須使用 OpenFileDialog 或 SaveFileDialog 顯示對話框時,可以使用 FileDialogPermission 類和 SecurityManager.IsGranted 靜態(tài)方法來檢查權限,如下所示。
FileDialogPermission fileDialogPermission = new FileDialogPermission( FileDialogPermissionAccess.Save ); if ( !SecurityManager.IsGranted( fileDialogPermission ) ) { // Not allowed to save file. }
如果您的應用程序設計成能從文件共享運行,您可以將該應用程序的地址設置為網(wǎng)絡共享(例如,\\MachineName\c$\YourAppPath\YourApp.exe)并從您的硬盤運行它來模擬這種方案。
如果您的應用程序設計成是從 Web Internet 區(qū)域運行,您可以使用您的計算機的 IP 地址(例如,\\<MachineIPaddress\c$\YourAppPath\YourApp.exe)來模擬這種方案。
Demand/Assert 模式用于完全受信任的程序集中,以允許部分受信任的調(diào)用程序在調(diào)用時訪問特權操作。當部分受信任的調(diào)用程序需要以安全的方式執(zhí)行特權操作而又不具有必要的特權時,這種模式非常有用。通過使用 Assert,您可以擔保您的代碼的調(diào)用程序是值得信任的。
注只有當您完全理解它的使用可能帶來的安全風險時,才能使用 Demand/Assert 模式。斷言權限關閉了正常的 .NET Framework 權限檢查,這種權限檢查會檢查堆棧中所有的調(diào)用代碼。關閉這種機制可能會將嚴重的安全漏洞引入代碼中,因此只有在您完全理解該模式的含義并用盡所有其他可能的解決方案時,才能嘗試這種模式。
在這種模式中,Demand 調(diào)用發(fā)生在 Assert 調(diào)用之前。Demand 查看調(diào)用程序是否具有該權限,然后,Assert 關閉特定權限的堆棧遍歷,這樣公共語言運行庫就不會檢查調(diào)用程序是否具有適當?shù)臋嘞蕖?div style="height:15px;">