反映可讓您取得類型和成員的相關信息,以及存取成員(也就是呼叫方法和建構函式、取得和設定屬性值、加入和移除事件處理程式等等)。 使用反射來取得類型和成員的相關資訊不受限制。 所有程式代碼都可以使用反映來執行下列工作:
- 列舉類型和成員,並檢查其元數據。
- 列舉和檢查元件和模組。
相反地,使用反射來存取成員會受到限制。 從 .NET Framework 4 開始,只有受信任的程式代碼可以使用反映來存取安全性關鍵成員。 此外,只有受信任的程式碼能使用反射來存取非公用成員,這些成員對於已編譯的程式碼是不可直接存取的。 最後,使用反映來存取安全關鍵成員的程式代碼必須具有安全關鍵成員要求的任何許可權,就像編譯的程式代碼一樣。
根據必要的權限,程式代碼可以使用反映來執行下列類型的存取:
存取非安全性關鍵的公共成員。
如果這些成員不是安全性關鍵,則存取可存取編譯程式代碼的非公用成員。 這類非公開成員的範例包括:
呼叫程式代碼基類的受保護成員。 (在反思中,被稱為家庭級存取權。)
internal
成員 (Friend
Visual Basic 中的成員) 在呼叫程式代碼的元件中。 在反思中,這被稱為組合層級存取。包含呼叫程式碼的類別之其他實例中的私有成員。
例如,除非應用程式域授與其他許可權,否則在沙盒化應用程式域中執行的程式代碼僅限於此清單中所述的存取權。
從 .NET Framework 2.0 Service Pack 1 開始,當嘗試存取通常無法存取的成員時,會產生一個包括目標物件的授權集以及附有ReflectionPermissionReflectionPermissionFlag.MemberAccess旗標的需求。 以完全信任執行的程式代碼(例如,從命令行啟動的應用程式中的程式碼,一律可以滿足這些許可權。 (這受限於存取安全性關鍵成員的限制,如本文稍後所述。
選擇性地,沙箱化的應用程式域可以使用ReflectionPermission旗標授予ReflectionPermissionFlag.MemberAccess,如本文稍後存取通常無法存取的成員一節所述。
存取 Security-Critical 成員
如果成員具有 SecurityCriticalAttribute,或者它屬於具有 SecurityCriticalAttribute的類型,或者它位於安全性關鍵元件中,那麼該成員就是安全性關鍵成員。 從 .NET Framework 4 開始,存取安全性關鍵成員的規則如下所示:
透明程式代碼無法使用反映來存取安全性關鍵成員,即使程式代碼完全受信任也一樣。 擲出MethodAccessException、FieldAccessException或TypeAccessException。
以部分信任執行的程式代碼會被視為透明。
不論安全性關鍵成員是直接透過編譯的程式代碼存取,還是使用反映來存取,這些規則都相同。
從命令列執行的應用程式碼以完全信任的方式運行。 只要它未標示為透明,就可以使用反映來存取安全性關鍵成員。 當相同的程式代碼以部分信任執行時(例如,在沙盒化應用程式域中),元件的信任層級會判斷它是否可以存取安全性關鍵程序代碼:如果元件具有強名稱,且已安裝在全域程式集緩存中,則它是信任的元件,而且可以呼叫安全性關鍵成員。 如果它不受信任,它就會變成透明,即使它未標示為透明,而且無法存取安全性關鍵成員。
反映和透明度
從 .NET Framework 4 開始,Common Language Runtime 會從數個因素決定類型或成員的透明度層級,包括元件的信任層級和應用程式域的信任層級。 反映提供 IsSecurityCritical、 IsSecuritySafeCritical和 IsSecurityTransparent 屬性,可讓您探索類型的透明度層級。 下表顯示這些屬性的有效組合。
安全性層級 | 是否具備安全關鍵性 | IsSecuritySafeCritical | IsSecurityTransparent |
---|---|---|---|
危急 | true |
false |
false |
安全至關重要 | true |
true |
false |
透明 | false |
false |
true |
使用這些屬性比檢查元件及其類型的安全性批注、檢查目前的信任層級,以及嘗試複製運行時間的規則簡單得多。 例如,從命令列執行時,相同的型別可能為安全性關鍵型別,而在沙盒化應用程式域中執行時則具有安全性透明性。
在MethodBase、FieldInfo、TypeBuilder、MethodBuilder和DynamicMethod類別上也有類似的屬性。 (對於其他反射和反射發出抽象概念,安全性屬性會套用至相關聯的方法,例如,在屬性存取子套用屬性的情況下。)
存取通常無法存取的成員
若要使用反射來叫用依據通用語言執行階段的可存取性規則原本無法存取的成員,您的程式代碼必須獲得兩項許可權中的其中一項。
若要允許程式碼叫用任何非公用成員,必須以 ReflectionPermission 旗標授予 ReflectionPermissionFlag.MemberAccess 程式碼許可。
備註
根據預設,安全策略會拒絕來自因特網的程式代碼此許可權。 此許可權絕不應授與源自因特網的程序代碼。
若要允許程式代碼能呼叫任何非公用成員,只要包含已呼叫成員的元件的授權集與包含呼叫程式代碼的元件的授權集相同或為其子集的一部分,您的程式代碼必須被授予具有ReflectionPermission旗標的ReflectionPermissionFlag.RestrictedMemberAccess。
例如,假設您授予應用程式域互聯網許可權以及 ReflectionPermission 和 ReflectionPermissionFlag.RestrictedMemberAccess 旗標,然後執行一個包含元件 A 和 B 的互聯網應用程式。
元件 A 可以使用反射來存取元件 B 的私人成員,因為元件 B 的授與集沒有包含任何未授與 A 的許可權。
元件 A 無法使用反射來存取 .NET Framework 元件的私人成員,例如 mscorlib.dll,因為 mscorlib.dll 完全受信任,因此具有尚未授予元件 A 的權限。當程式碼在執行時間執行堆疊遍歷以進行存取安全性時,會擲回 MemberAccessException。
序列化
針對串行化, SecurityPermission 使用 SecurityPermissionAttribute.SerializationFormatter 旗標可讓您取得和設定可串行化類型的成員,而不論存取範圍為何。 此許可權可讓程式代碼探索和變更實例的私人狀態。 (除了授予適當的權限之外,型別必須在元數據中 標示 為可串行化。)
類型 MethodInfo 的參數
請避免撰寫接受 MethodInfo 參數的公用成員,特別是針對受信任的程序代碼。 這類成員可能更容易受到惡意代碼的影響。 例如,請考慮在高度信任的程式碼中採用 MethodInfo 參數的公開成員。 假設公用成員間接呼叫提供的參數中的 Invoke 方法。 如果公共成員未進行必要的權限檢查,則對 Invoke 方法的呼叫將一律成功,因為安全系統會認為呼叫者具有高度信任。 即使惡意代碼沒有直接叫用方法的許可權,仍可藉由呼叫公用成員來間接執行此動作。
版本資訊
從 .NET Framework 4 開始,透明程式代碼無法使用反映來存取安全性關鍵成員。
旗 ReflectionPermissionFlag.RestrictedMemberAccess 標是在 .NET Framework 2.0 Service Pack 1 中引進的。 舊版的 .NET Framework 需要使用 ReflectionPermissionFlag.MemberAccess 旗標來讓程式碼透過反射存取非公用成員。 這是絕對不應該授與部分信任程式代碼的許可權。
從 .NET Framework 2.0 開始,使用反射取得非公用類型和成員的資訊不需要任何權限。 在舊版中,必須使用具有ReflectionPermission標誌的ReflectionPermissionFlag.TypeInformation。