Security Considerations for Reflection

Reflection provides the ability to obtain information about types and members, and to access members (that is, to call methods and constructors, to get and set property values, to add and remove event handlers, and so on). The use of reflection to obtain information about types and members is not restricted. All code can use reflection to perform the following tasks:

Enumerate types and members, and examine their metadata.

Enumerate and examine assemblies and modules.

Using reflection to access members, by contrast, is subject to restrictions. Beginning with the .NET Framework version 4, only trusted code can use reflection to access security-critical members. Furthermore, only trusted code can use reflection to access nonpublic members that would not be directly accessible to compiled code. Finally, code that uses reflection to access a safe-critical member must have whatever permissions the safe-critical member demands, just as with compiled code.

Subject to necessary permissions, code can use reflection to perform the following kinds of access:

Access public members that are not security-critical.

Access nonpublic members that would be accessible to compiled code, if those members are not security-critical. Examples of such nonpublic members include:

Protected members of the calling code's base classes. (In reflection, this is referred to as family-level access.)

internal members (Friend members in Visual Basic) in the calling code's assembly. (In reflection, this is referred to as assembly-level access.)

Private members of other instances of the class that contains the calling code.

For example, code that is run in a sandboxed application domain is limited to the access described in this list, unless the application domain grants additional permissions.

Starting with the .NET Framework version 2.0 Service Pack 1, attempting to access members that are normally inaccessible generates a demand for the grant set of the target object plus ReflectionPermission with the ReflectionPermissionFlag.MemberAccess flag. Code that is running with full trust (for example, code in an application that is launched from the command line) can always satisfy these permissions. (This is subject to limitations in accessing security-critical members, as described later in this article.)

A member is security-critical if it has the SecurityCriticalAttribute, if it belongs to a type that has the SecurityCriticalAttribute, or if it is in a security-critical assembly. Beginning with the .NET Framework version 4, the rules for accessing security-critical members are as follows:

These rules are the same whether a security-critical member is accessed directly by compiled code, or accessed by using reflection.

Application code that is run from the command line runs with full trust. As long as it is not marked as transparent, it can use reflection to access security-critical members. When the same code is run with partial trust (for example, in a sandboxed application domain) the assembly's trust level determines whether it can access security-critical code: If the assembly has a strong name and is installed in the global assembly cache, it is a trusted assembly and can call security-critical members. If it is not trusted, it becomes transparent even though it was not marked as transparent, and it cannot access security-critical members.

Beginning with the .NET Framework 4, the common language runtime determines the transparency level of a type or member from several factors, including the trust level of the assembly and the trust level of the application domain. Reflection provides the IsSecurityCritical, IsSecuritySafeCritical, and IsSecurityTransparent properties to enable you to discover the transparency level of a type. The following table shows the valid combinations of these properties.

Security level

IsSecurityCritical

IsSecuritySafeCritical

IsSecurityTransparent

Critical

true

false

false

Safe-critical

true

true

false

Transparent

false

false

true

Using these properties is much simpler than examining the security annotations of an assembly and its types, checking the current trust level, and attempting to duplicate the runtime's rules. For example, the same type can be security-critical when it is run from the command line, or security-transparent when it is run in a sandboxed application domain.

There are similar properties on the MethodBase, FieldInfo, TypeBuilder, MethodBuilder, and DynamicMethod classes. (For other reflection and reflection emit abstractions, security attributes are applied to the associated methods; for example, in the case of properties they are applied to the property accessors.)

Assembly A can use reflection to access private members of assembly B, because the grant set of assembly B does not include any permissions that A has not been granted.

Assembly A cannot use reflection to access private members of .NET Framework assemblies such as mscorlib.dll, because mscorlib.dll is fully trusted and therefore has permissions that have not been granted to assembly A. A MemberAccessException is thrown when code access security walks the stack at run time.

For serialization, SecurityPermission with the SecurityPermissionAttribute.SerializationFormatter flag provides the ability to get and set members of serializable types, regardless of accessibility. This permission enables code to discover and change the private state of an instance. (In addition to being granted the appropriate permissions, the type must be marked as serializable in metadata.)

Avoid writing public members that take MethodInfo parameters, especially for trusted code. Such members might be more vulnerable to malicious code. For example, consider a public member in highly trusted code that takes a MethodInfo parameter. Assume that the public member indirectly calls the Invoke method on the supplied parameter. If the public member does not perform the necessary permission checks, the call to the Invoke method will always succeed, because the security system determines that the caller is highly trusted. Even if malicious code does not have the permission to directly invoke the method, it can still do so indirectly by calling the public member.

Beginning with the .NET Framework version 4, transparent code cannot use reflection to access security-critical members.

The ReflectionPermissionFlag.RestrictedMemberAccess flag is introduced in the .NET Framework version 2.0 Service Pack 1. Earlier versions of the .NET Framework require the ReflectionPermissionFlag.MemberAccess flag for code that uses reflection to access nonpublic members. This is a permission that should never be granted to partially trusted code.

Beginning with the .NET Framework 2.0, using reflection to obtain information about nonpublic types and members does not require any permissions. In earlier versions, ReflectionPermission with the ReflectionPermissionFlag.TypeInformation flag is required.