反映發出中的安全性問題

更新:2007 年 11 月

.NET Framework 提供三種發出 Microsoft Intermediate Language (MSIL) 的方式,每一種方式本身都有安全性問題:

  • 動態組件

  • 匿名裝載動態方法

  • 與現有組件關聯的動態方法

無論您使用哪種方法產生動態程式碼,在執行產生的程式碼時都需要產生之程式碼使用的型別和方法所需的使用權限。

注意事項:

反映程式碼和發出程式碼所需的使用權限在 .NET Framework 的後續版本中已變更。請參閱本主題稍後提及的版本資訊。

動態組件

動態組件是使用 AppDomain.DefineDynamicAssembly 方法的多載所建立,所需的使用權限需視使用的多載而定。例如,提供辦識項的多載需要含有 SecurityPermissionFlag.ControlEvidence 旗標的 SecurityPermission。某些多載不需要使用權限,可以從僅具有網際網路使用權限的程式碼呼叫。

動態組件內的程式碼可以存取其他組件內的可見型別和成員。

注意事項:

動態組件不會使用 ReflectionPermissionFlag.MemberAccessReflectionPermissionFlag.RestrictedMemberAccess 旗標來允許動態方法存取非公用的型別和成員。

產生具有偵錯符號的程式碼需要具有 ReflectionPermissionFlag.ReflectionEmit 旗標的 ReflectionPermission

暫時性 (Transient) 的動態組件會在記憶體內建立,而且永遠不會儲存到磁碟中,因此不需要檔案存取權限。將動態組件儲存至磁碟需要具有適當旗標的 FileIOPermission

從部分信任的程式碼產生動態組件

請考慮某種情況,具有網際網路使用權限的組件可以產生暫時性動態組件並執行其程式碼:

  • 動態組件只會使用其他組件的公用型別和成員。

  • 由那些型別和成員要求的使用權限包含在部分信任組件的授權集中。

  • 用於建立動態組件的 DefineDynamicAssembly 方法多載不需要特殊的使用權限 (那表示,沒有提供辦識項,依此類推)。

  • 組件不會儲存至磁碟。

  • 不會產生偵錯符號 (Internet 和 LocalIntranet 使用權限集不會包含 ReflectionPermissionFlag.ReflectionEmit 旗標)。

建立動態組件的使用權限

在下列清單中,「發出器」是一個組件,會產生動態組件。

  • 具有含 SecurityPermissionFlag.ControlEvidence 旗標之 SecurityPermission 的發出器可以為產生的程式碼提供辦識項。這個辨識項透過原則來對應,以決定授與的使用權限。

  • 發出器可以提供 null 辨識項,如果是這樣,組件將取得發出器的使用權限集合。這確保產生的程式碼不會有較其發出器更大的使用權限。

  • 如果您提供的使用權限集具有 SecurityAction.RequestMinimumSecurityAction.RequestOptionalSecurityAction.RequestRefuse,則除非組件已儲存至磁碟,並於隨後從磁碟載入,否則不會使用那些使用權限集。

  • 動態組件一旦儲存至磁碟後,就會被視為其他已從磁碟載入的組件。

  • 由非完全信任發出器產生的程式碼一定會經過驗證。特別是,執行階段一定會驗證程式碼中不含 SecurityPermissionFlag.SkipVerification 旗標的 SecurityPermission。完全受信任的發出器可以略過驗證,或者要求產生的程式碼接受驗證。

匿名裝載動態方法

匿名裝載動態方法是使用兩種沒有指定相關聯型別或模組的 DynamicMethod 建構函式 (即 DynamicMethod(String, Type, array<Type[])DynamicMethod(String, Type, array<Type[], Boolean)) 來建立。這些建構函式會將動態方法置放在一個系統提供、完全受信任、安全性透明的組件中。使用這些建構函式或使用動態方法的發出程式碼時,不需要任何使用權限。

建立匿名裝載動態方法時,會改為擷取呼叫堆疊。建構方法時,會針對已擷取的呼叫堆疊產生安全性要求。

注意事項:

在概念上來說,這些要求是在方法建構期間產生的。那表示,這些要求可以在發出每個 MSIL 指令時產生。在目前的實作中,如果叫用方法時未呼叫 CreateDelegate,則所有的要求都會在呼叫 DynamicMethod.CreateDelegate 方法時產生,或在叫用 Just-In-Time (JIT) 編譯器時產生。

在下列限制下,匿名裝載動態方法可以略過 JIT 可視性檢查:由匿名裝載動態方法存取的非公用型別和成員必須位於與發出呼叫堆疊的授權集相等的授權集組件,或發出呼叫堆疊之授權集的子集。在這項限制下,要略過 JIT 可視性檢查,就需要具有 ReflectionPermissionFlag.RestrictedMemberAccess 旗標的 ReflectionPermission

  • 如果您的方法只會使用公用型別和成員,則在建構期間不需要使用權限。

  • 如果您指定應該略過 JIT 可視性檢查,則在建構方法時,所產生的要求包括內含 ReflectionPermissionFlag.RestrictedMemberAccess 旗標的 ReflectionPermission,以及包含正在存取非 Public 成員之組件的授權集。

由於已將非 Public 成員的授權集納入考量,已授與 ReflectionPermissionFlag.RestrictedMemberAccess 的部分信任程式碼將無法藉由執行受信任組件的非 Public 成員來提高其權限。

跟任何其他發出的程式碼一樣,執行動態方法所需的使用權限都會由動態方法使用的方法發出要求。

如需詳細資訊,請參閱 DynamicMethod 類別。

從部分信任程式碼產生匿名裝載動態方法

請考慮某種情況,具有網際網路使用權限的組件可以產生匿名裝載動態方法並執行該方法:

  • 動態方法只會使用公用型別和成員。如果其授權集包含 ReflectionPermissionFlag.RestrictedMemberAccess,則可以使用與發出組件之授權集相等的任何組件之非公用型別和成員,或發出組件之授權集的子集。

  • 由動態方法使用的所有型別和成員要求的使用權限會包含在部分信任組件的授權集中。

注意事項:

動態方法不支援偵錯符號。

與現有組件關聯的動態方法

若要讓動態方法與現有組件內的型別或模組產生關聯,請使用任何一個指定關聯型別或模組的 DynamicMethod 建構函式來進行。呼叫這些建構函式時的必要使用權限有所不同,因為將動態方法與現有型別或模組產生關聯會提供存取非公用型別和成員的動態方法:

  • 與型別相關聯的動態方法可存取該型別的所有成員 (甚至是 Private 成員),以及存取包含相關聯型別之組件的所有 Internal 型別和成員。

  • 與模組相關聯的動態方法可以存取模組內所有 internal 型別和成員 (在 Visual Basic 內則為 Friend,在 Common Language Runtime 中繼資料內則為 assembly)。

此外,您可以使用指定要略過 JIT 編譯器之可視性檢查的建構函式。這麼做可讓您的動態方法存取所有組件內的所有型別和成員,不管其存取層級為何。

建構函式要求的使用權限需視您決定給予讓動態方法的存取層級而定:

雖然此清單內的項目是從發出組件的授權集觀點來描述,不過請記住,這些要求是針對完整的呼叫堆疊而產生的,包括應用程式定義域界限。

如需詳細資訊,請參閱 DynamicMethod 類別。

從部分信任的程式碼產生動態方法

注意事項:

從部分信任的程式碼產生動態方法的建議方式,是使用匿名裝載動態方法來進行。

請考慮某種情況,具有網際網路使用權限的組件可以產生動態方法並執行該方法:

  • 動態方法會與其發出的模組或型別產生關聯,或者其授權集會包含 ReflectionPermissionFlag.RestrictedMemberAccess,且會在與發出組件授權集相等之組件內的模組產生關聯,或與發出組件授權集的子集產生關聯。

  • 動態方法只會使用公用型別和成員。如果其授權集包含 ReflectionPermissionFlag.RestrictedMemberAccess,且其與和發出組件之授權集相等的組件內模組產生關聯,或者和發出組件之授權集的子集產生關聯,則可以使用關聯模組內標記為 internal (在 Visual Basic 內為 Friend,在 Common Language Runtime 中繼資料內為 assembly) 的型別和成員。

  • 由動態方法使用的所有型別和成員要求的使用權限會包含在部分信任組件的授權集中。

  • 動態方法不會略過 JIT 可視性檢查。

注意事項:

動態方法不支援偵錯符號。

版本資訊

從 .NET Framework 2.0 版 Service Pack 1 開始,在發出動態組件和動態方法時,不再需要含 ReflectionPermissionFlag.ReflectionEmit 旗標的 ReflectionPermission。在所有舊版的 .NET Framework 中則需要使用這個旗標。

注意事項:

ReflectionPermissionFlag.ReflectionEmit 旗標的 ReflectionPermission 預設會包含在 FullTrust 和 LocalIntranet 具名使用權限集合中,而非 Internet 使用權限集中。因此,在舊版 .NET Framework 中,只有當程式庫執行 ReflectionEmitAssert 時,才可以透過網際網路使用權限來使用該程式庫。這類程式庫需要經審慎的安全性檢閱,因為程式碼錯誤可能會產生安全性漏洞。.NET Framework 2.0 SP1 允許程式碼在部分信任案例中發出而不會發出任何安全性要求,因為產生程式碼本身並非特殊權限操作。也就是說,產生的程式碼不會有比發出它的組件更大的使用權限。這會允許發出程式碼的程式庫成為安全性透明,而無須判斷提示 (Assert) ReflectionEmit,如此可簡化撰寫安全程式庫的工作。

此外,.NET Framework 2.0 SP1 還新增 ReflectionPermissionFlag.RestrictedMemberAccess 旗標,以便從部分信任的動態方法中存取非公用型別和成員。舊版的 .NET Framework 需要 ReflectionPermissionFlag.MemberAccess 旗標,才能讓動態方法存取非公用型別和成員,這是一種永遠都不應該授與部分信任程式碼的使用權限。

最後,.NET Framework 2.0 SP1 加入了匿名裝載方法。

若要使用這些功能,您的應用程式應將目標設為 .NET Framework 3.5 版。如需詳細資訊,請參閱 .NET Framework 3.5 架構

取得型別和成員的資訊

從 .NET Framework 2.0 開始,在取得與非公用型別和成員相關的資訊時,已不需要使用權限。反映 (Reflection) 可用於取得發出動態方法所需的資訊。例如,MethodInfo 物件可用來發出方法呼叫。舊版 .NET Framework 需要具有含 ReflectionPermissionFlag.TypeInformation 旗標的 ReflectionPermission。如需詳細資訊,請參閱反映的安全性考量

請參閱

概念

反映的安全性考量

其他資源

發出動態方法和組件