前言
當建立一個 AppDomain 時,我們也可以修改它的屬性設定以適應要載入的組件。 例如,當我們想載入一個不明的組件到某個 AppDomain ,我們可以建立一個較小使用權限的 AppDomain ,以降低安全性弱點的風險。 AppDomain 不僅可以提供隔離單位,還可以降低被攻擊時所可能造成的損害。 尤其當呼叫組件執行時,適當的限制 AppDomain 的權限,將可大大減少惡意行為風險的發生。 例如,當我們使用一個外購的組件進行指定目錄的備份監控,要如何肯定這個程式不會讀取其他目錄的資料呢?或者如何提防它是否會透過網路將資料外傳呢? 反之,當我們設計一個組件,若沒有做任何安全性的限制,它會不會變成漏洞,反而被其他組件拿來當成跳板,執行不該有的行為呢?
如何使用 AppDomain 限制 Assembly 啟動時的權限
要限制 AppDomain 組態,有許多方式,本節僅要說明如何使用識別項 (Evidence) 來設定 AppDomain 的組態。
.NET Framework針對程式碼在執行時,內建三個安全性原則(Policy):企業、電腦及使用者。 每個原則下管理著一群程式碼群組(Code Group),每個程式碼群組繫結一個權限集合,整個展開如下圖
PS.程式碼存取安全性 (CAS) 的原則部分在 .NET Framework 4 版中已經過時,不再適用。 因此,如果以明確或隱含方式 (透過其他類型和成員) 呼叫過時的原則類型與成員,您可能會遇到編譯警告與執行階段例外狀況。 詳情請參考程式碼存取安全性原則相容性和移轉 。
辨識項(Evidence)
辨識項(Evidence)是構成安全性原則的資訊集,定義了組件在執行階段的安全性原則,簡單講就是指明組件是屬於哪些程式碼群組。 換句話說,就是程式碼群組控制了組件的權限。若要限定組件的使用權限,就可以指派一個 Evidence 給組件。
當建立 AppDomain ,並載入某個組件執行,這個時候會擁有對該組件 Evidence 的完全控制權。 Evidence 記載了一些資訊,指明該組件屬於哪些程式碼群組 (Code Group),而程式碼群組則可以決定該組件的權限。
通用的 Evidence 裏,記載了組件是從哪個資料夾或網站執行,以及數位簽章。 不過 Evidence 其實可以是由任何型別的物件構成,如數字,字串,自訂型別等。 只要將這些型別,以物件陣列 (object[]) 的型式組成,就可以建構 Evidence 類別。
Evidence Class
[SerializableAttribute] [ComVisibleAttribute(true)] public sealed class Evidence : ICollection, IEnumerable
Evidence Consturctor
public Evidence( Object[] hostEvidence, //hostEvidence :用來建立新執行個體的主應用程式辨識項。 Object[] assemblyEvidence //assemblyEvidence:用來建立新執行個體的組件辨識項。 )
// Evidence 由 object [] 構成, // 而 object [] 內可以是任何型別 object[] hostEvidence = { new Zone(SecurityZone.Internet) , 10, "test" }; Evidence ev1 = new Evidence(hostEvidence, null); ev1.AddHost(new Uri("http://www.microsoft.com"));
Evidence 可以指定給 Assembly 或 AppDomain。
若要指定給 Assembly,就在 AppDomain.ExecuteAssembly 時指定;
若要指定給 AppDomain,就在 AppDomain.CreateDomain 時指定。
如何提供主機辨識項給組件
透過指派 Evidence 給某個組件,就可以控制該組件的使用權限。 若要指派 Evidence 給某個組件,必須先建立一個 System.Security.Policy.Evidence 物件,然後將它傳給 AppDomain.ExecuteAssembly 。
下面這段程式碼將示範: 如何將指定的組件限定在一個獨立的 AppDomain 中執行,並且僅授與 Internet_Zone 程式碼群組的使用權限集合。 當 AppDomain 啟動該組件時,系統會根據它提供的 Evidence 內容,將它指派給 Internet_Zone 這個程式碼群組。 Zone evidence 是.Net內建的一種辨識項,定義了極嚴格的 Internet 使用權限集,我們可以將它指派給 AppDomian 中的組件,以限定組件的權限。
public enum SecurityZone { NoZone = -1, //未指定區域。 MyComputer = 0, //本機電腦區域 Intranet = 1, //近端內部網路區域 Trusted = 2, //信任的網站區域 Internet = 3, //網際網路區域 Untrusted = 4, //限制的網站區域,需要將未受信任網站的 URL 對應至這個區域。 }
//===================================================================================== //將組件建立隔離在一個叫 NewDomain 的 AppDomain 之下,並授與 Internet_Zone 程式碼群組的使用權限集合。 //===================================================================================== //1)建立主機辨識項 object[] codeGroup = { new Zone(SecurityZone.Internet) }; //建立包含 Internet_Zone 的程式碼群組 Evidence hostEvidence = new Evidence(codeGroup, null); //2)建立AppDomain AppDomain newDomain = AppDomain.CreateDomain("NewDomain"); //3)執行組件,並指定一個 Evidence 物件 newDomain.ExecuteAssembly(@"D:\MCTS\MCTS2011\Practice\WindowsFormsApplication1\bin\Debug\WindowsFormsApplication1.exe", hostEvidence);
上面程式碼,由於ExecuteAssembly(String, Evidence)這個建構子已過時,所以會產生以下錯誤。
除非改用其他沒有過時的建構子,要不然可參考以下兩種方式:
- 1. 改以.NET4.0方式取代過時的呼叫:
- Assembly.PermissionSet
- Assembly.IsFullyTrusted
- AppDomain.PermissionSet
- AppDomain.IsFullyTrusted
- 2. 使用舊版CAS原則 (在Configuration使用NetFx40_LegacySecurityPolicy設定)
若暫時不想修改程式可以使用這個方法,在App.config增加一個<runtime>項目,並將NetFx40_LegacySecurityPolicy的enabled屬性設定為True,表是使用舊版的CAS程式碼安全性原則。
<configuration> <runtime> <NetFx40_LegacySecurityPolicy enabled="true"/> </runtime> </configuration>
若採用第二種方式進行修改,程式碼就可正常編譯執行。 不過,在上面這個例子中的 WindowsFormsApplication1.exe 這個組件,我們原本是利用它去開啟C糟某個文字檔,當它單獨被執行的時候是正常的。 但是,若使用 Evidence 指派 SecurityZone.Internet 權限後,當組件被執行後,畫面會出現如下警告訊息(左圖)。 並且,當程式嗎執行到 File IO 時,也會發生 SecurityException (右圖)。若將程式碼中的 SecurityZone.Internet 變更成 SecurityZone.MyComputer 就沒問題,因為 MyComputer Zone 具有讀取該檔案的權利。
如何提供主機辨識項給應用程式定義域
//1)建立主機辨識項 object[] codeGroup = { new Zone(SecurityZone.Internet) }; Evidence hostEvidence = new Evidence(codeGroup, null); //2)建立AppDomain,並指定一個 Evidence 物件 AppDomain newDomain = AppDomain.CreateDomain("NewDomain", hostEvidence); //3)執行組件,若沒特別設定,皆會套用與 AppDomain 相同 Evidence 物件 newDomain.ExecuteAssembly(@"D:\MCTS\MCTS2011\Practice\WindowsFormsApplication1\bin\Debug\WindowsFormsApplication1.exe");
如何設定AppDomain Properties
要設定 AppDomain 的屬性,必須透過 AppDomainSetup 類別。
若只是單純的變更 AppDomainSetup 的執行個體並不會影響任何已經存在的 AppDomain 的屬性。
它必須當成 AppDomain.CreateDomain 方法執行時的參數,並且只會對新建立的 AppDomain 有效。
使用 AppDomainSetup 設定 AppDomain 屬性
// 設定 AppDomain 屬性 AppDomainSetup domainProperty = new AppDomainSetup(); domainProperty.ApplicationBase = "file://" + System.Environment.CurrentDirectory; //取得應用程式的目錄名稱。 domainProperty.DisallowBindingRedirects = false; //是否允許組件繫結重新導向 domainProperty.DisallowCodeDownload = true; //是否允許以 HTTP 下載組件 domainProperty.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; //設定 AppDomain 的組態檔的位置 // 建立新的應用程式定義域,並以 AppDomainSetup 設定 AppDomain 的屬性。 AppDomain newDomain = AppDomain.CreateDomain("New Domain", null, domainProperty);
檢視目前 AppDomain 的屬性
透過 AppDomain.SetupInformation 屬性,可取得應用程式定義域的屬性設定值。
//檢視AppDomain目前的設定值 AppDomainSetup domainProperty2 = AppDomain.CurrentDomain.SetupInformation; //取得目前應用程式定義域的屬性 Console.WriteLine(domainProperty2.ApplicationBase); Console.WriteLine(domainProperty2.ApplicationName); Console.WriteLine(domainProperty2.DisallowCodeDownload); Console.WriteLine(domainProperty2.DisallowBindingRedirects); Console.WriteLine(domainProperty2.ConfigurationFile); //D:\......\bin\Debug\ //PracticeMCTS.vshost.exe //False //False //D:\......\bin\Debug\PracticeMCTS.vshost.exe.Config
附註:
以下截至 MSDN .NET Framework 4 中的安全性變更
從 .NET Framework 4 開始,CLR 不會為電腦提供安全性原則。 以往,.NET Framework 會提供程式碼存取安全性 (CAS) 原則當做嚴格控制和設定 Managed 程式碼功能的機制。 雖然 CAS 原則的功能很強大,不過它可能很複雜而且限制較多。 而且,因為 CAS 也不支援原生應用程式,所以在安全性保證上會有所限制。 在 Windows 7 和 Windows Server 2008 R2 上,系統管理員應該尋求 Windows 軟體限制原則 (Software Restriction Policies , SRP) 或 AppLocker 等作業系統層級解決方案當做 CAS 原則的取代項目。 SRP 和 AppLocker 原則會提供同時適用於 Managed 程式碼和機器碼的簡單信任機制。就安全性原則解決方案而言,SRP 和 AppLocker 會比 CAS 更簡單而且提供較佳的安全性保證。
非裝載的應用程式 (亦即,透過 [Windows 檔案總管] 或從命令提示字元執行的應用程式) 現在會以完全信任執行。這包括位於區域網路上共用的應用程式。 裝載或沙箱應用程式會繼續使用其主機 (例如 Internet Explorer、ClickOnce 或 ASP.NET) 所決定的信任原則來執行。 在沙箱中執行的應用程式或控制項會被視為部分信任的。
沒有留言:
張貼留言