.NET Framework 提供三種方式來發出通用中繼語言 (CIL),每個都有其本身的安全性問題:
不論您產生動態程式代碼的方式為何,執行產生的程式代碼都需要所產生程式代碼所使用的類型和方法所需的所有許可權。
備註
反映程式代碼和發出程序代碼所需的許可權已隨著 .NET Framework 的後續版本而變更。 請參閱本文稍後 的版本資訊。
動態組件
動態程式集是使用AppDomain.DefineDynamicAssembly方法的多載所建立。 由於取消全機器安全策略,此方法的大部分多載在 .NET Framework 4 中已被取代。 不論信任層級為何,其餘的多載都可以由任何程式代碼執行。 這些多載分為兩個群組:一種指定在建立動態集合時應用的屬性清單,另一種則不指定屬性清單。 如果您未指定元件的透明度模型,請在建立元件時套用 SecurityRulesAttribute 屬性,透明度模型會繼承自發出元件。
備註
在建立動態元件之後,使用 SetCustomAttribute 方法套用至動態組件的屬性,這些屬性在元件儲存到磁碟並再次載入記憶體之前,不會生效。
動態元件中的程式代碼可以存取其他元件中的可見類型和成員。
備註
動態元件不使用允許動態方法存取非公用類型和成員的 ReflectionPermissionFlag.MemberAccess 和 ReflectionPermissionFlag.RestrictedMemberAccess 旗標。
暫時性動態元件會在記憶體中建立,且永遠不會儲存至磁碟,因此不需要檔案訪問許可權。 將動態組件儲存到磁碟需要使用適當的旗標和 FileIOPermission 。
從部分信任的程式碼生成動態組件
請考慮具有因特網許可權的元件可以產生暫時性動態元件並執行其程式代碼的條件:
動態組件只會使用公用類型和其他組件的成員。
這些類型和成員所要求的許可權會納入部分信任組件的授與集合中。
元件不會儲存至磁碟。
不會產生偵錯符號。 (
Internet和LocalIntranet許可權集合不包含必要的許可權。
匿名託管的動態方法
匿名託管的動態方法是透過使用兩個不指定相關類型或模組的建構函式來創建,即DynamicMethod 和DynamicMethod(String, Type, Type[])。 這些建構函式會將動態方法放置在系統提供的、具有完全信任和安全性透明的組件中。 使用這些建構函式或發出動態方法的程式代碼不需要任何許可權。
當動態方法在匿名寄存中被建立時,會擷取呼叫堆疊。 建構 方法時,會針對擷取的呼叫堆疊提出安全性需求。
備註
就概念上講,在方法建構期間會提出要求。 也就是說,當發出每個 CIL 指令時,要求可能會被提出。 在目前的實作中,當呼叫DynamicMethod.CreateDelegate方法時,或者如果在沒有呼叫CreateDelegate的情況下直接由即時(JIT)編譯器叫用方法時,系統都會發出所有要求。
如果應用程式域允許,匿名承載的動態方法可以略過 JIT 可見性檢查,但需遵守以下限制:匿名承載動態方法存取的非公開類型及成員必須位於其授權集等於或為發出程式碼的呼叫堆疊授權集的子集的組件中。 如果應用程式域授 ReflectionPermission 與 ReflectionPermissionFlag.RestrictedMemberAccess 旗標,則會啟用略過 JIT 可見度檢查的限制功能。
如果您的方法只使用公用類型和成員,則建構期間不需要任何許可權。
如果您指定應該略過 JIT 可見度檢查,則建構方法時所做的要求會包含ReflectionPermissionReflectionPermissionFlag.RestrictedMemberAccess旗標和包含要存取之非公用成員的元件授與集。
由於已考慮到非公用成員的授與範圍,因此已獲得 ReflectionPermissionFlag.RestrictedMemberAccess 授權的部分信任程式代碼無法通過執行受信任組件的非公用成員來提升其許可權。
如同任何其他發出的程式代碼,執行動態方法需要動態方法所使用的方法所要求的任何許可權。
裝載匿名裝載動態方法的系統元件會使用 SecurityRuleSet.Level1 透明度模型,這是 .NET Framework 4 之前在 .NET Framework 中使用的透明度模型。
如需詳細資訊,請參閱 DynamicMethod 類別。
從部分信任的程式碼產生匿名託管的動態方法
請考慮具有因特網許可權的元件可以產生匿名裝載的動態方法並加以執行的條件:
動態方法只會使用公用類型和成員。 如果其授與集包含 ReflectionPermissionFlag.RestrictedMemberAccess,則可以使用任何屬於授與集等於或是發出元件之授與集的一個子集的組件中的非公共類型和成員。
動態方法所使用的所有類型和成員所需的許可權會包含在部分信任元件的授與集內。
備註
動態方法不支援偵錯符號。
與現有元件相關聯的動態方法
若要將動態方法與現有元件中的類型或模組產生關聯,請使用任何指定相關聯型別或模組的 DynamicMethod 建構函式。 呼叫這些建構函式所需的許可權會有所不同,因為將動態方法與現有的類型或模組產生關聯,因此會提供非公用類型和成員的動態方法存取權:
與類型相關聯的動態方法可以存取該類型的所有成員,甚至是私人成員,以及包含相關聯型別之元件中的所有內部類型和成員。
與模組相關聯的動態方法可以存取模組中的所有
internal類型和成員(在 Visual Basic 中為Friend,在通用語言執行平台元數據中為assembly)。
此外,您可以使用建構函式來指定略過 JIT 編譯程式可見度檢查的能力。 這樣做可讓您的動態方法存取所有元件中的所有類型和成員,而不論存取層級為何。
建構子所要求的許可權取決於您決定為動態方法授予的存取權。
如果您的方法只使用公用類型和成員,而且您將它與您自己的類型或您自己的模組產生關聯,則不需要任何許可權。
如果您指定應該略過 JIT 可見性檢查,則建構函式要求使用帶有 ReflectionPermission 旗標的 ReflectionPermissionFlag.MemberAccess。
如果您將動態方法與另一個類型建立關聯,甚至是在您自己的元件中的另一個類型,則建構函式要求含有 ReflectionPermission 旗標的 ReflectionPermissionFlag.MemberAccess 和含有 SecurityPermission 旗標的 SecurityPermissionFlag.ControlEvidence。
如果您將動態方法與另一個元件中的類型或模組產生關聯,建構函式會要求兩件事: ReflectionPermission 搭配 ReflectionPermissionFlag.RestrictedMemberAccess 旗標,以及包含另一個模組的元件授與集。 也就是說,您的呼叫堆疊必須包含目標模組授與集中的所有許可權,再加上 ReflectionPermissionFlag.RestrictedMemberAccess。
備註
為了回溯相容性,如果目標授與集的需求加上 ReflectionPermissionFlag.RestrictedMemberAccess 無法成功,則建構函式會要求 SecurityPermission 並具有 SecurityPermissionFlag.ControlEvidence 旗標。
雖然這份清單中的專案會以發出元件的授予集來說明,但請記住,對整個呼叫堆疊的需求包含應用程式域的邊界。
如需詳細資訊,請參閱 DynamicMethod 類別。
從部分信任的程式代碼產生動態方法
備註
從部分信任的程式代碼產生動態方法的建議方式是使用 匿名裝載的動態方法。
請考慮具有因特網許可權的元件可以產生動態方法並加以執行的條件:
動態方法會與發出它的模組或類型相關聯,或其授與集包含 ReflectionPermissionFlag.RestrictedMemberAccess ,而且與授與集等於或發出元件之授與集子集的模組相關聯。
動態方法只會使用公用類型和成員。 如果其授與集包含 ReflectionPermissionFlag.RestrictedMemberAccess ,並且其關聯的模組為所在元件的授與集等於或是發出組件授與集的子集,則可以使用相關聯模組中標注
internal的類型和成員(在 Visual Basic 中為Friend,在通用語言運行時元數據中為assembly)。動態方法所使用的所有類型和成員所要求的許可權會包含在部分信任元件的授與集內。
動態方法不會略過 JIT 可見性檢查。
備註
動態方法不支援偵錯符號。
版本資訊
從 .NET Framework 4 開始,會消除全機器的安全策略,且安全性透明度會成為默認強制執行機制。
從 .NET Framework 2.0 Service Pack 1 開始,發出動態組件和動態方法時,不再需要使用ReflectionPermission旗標。 所有舊版 .NET Framework 都需要此旗標。
備註
ReflectionPermission 與 ReflectionPermissionFlag.ReflectionEmit 旗標預設包含在 FullTrust 和 LocalIntranet 的具名許可權集合中,但不包含在 Internet 的許可權集合中。 因此,在舊版 .NET Framework 中,程式庫只有在執行 Assert 於 ReflectionEmit 時才能使用網路權限。 這類連結庫需要仔細的安全性檢閱,因為編碼錯誤可能會導致安全性漏洞。 .NET Framework 2.0 SP1 允許在部分信任案例中發出程式代碼,而不會發出任何安全性需求,因為產生程式代碼原本就不是特殊許可權作業。 也就是說,產生的程式代碼擁有的許可權不超過發出它的組件。 這可讓產生程式碼的庫成為安全透明,並移除宣告ReflectionEmit的需求,這簡化了撰寫安全庫的工作。
此外,.NET Framework 2.0 SP1 引進 ReflectionPermissionFlag.RestrictedMemberAccess 旗標,可從部分信任的動態方法存取非公用類型和成員。 舊版 .NET Framework 需要 ReflectionPermissionFlag.MemberAccess 標記來存取非公有類型和成員的動態方法;這是絕對不應該授與部分信任的程式碼的權限。
最後,.NET Framework 2.0 SP1 引進匿名裝載的方法。
取得類型和成員的相關信息
從 .NET Framework 2.0 開始,不需要任何許可權才能取得非公用類型和成員的相關信息。 反射用于獲取生成動態方法所需的資訊。 例如, MethodInfo 對象可用來發出方法呼叫。 舊版 .NET Framework 需要 ReflectionPermission 具有 ReflectionPermissionFlag.TypeInformation 旗標。 如需詳細資訊,請參閱 反射的安全性考量。