.NET Framework 2.0 Security Guidelines - Reflection

From Guidance Share

Jump to: navigation, search

- J.D. Meier, Alex Mackman, Blaine Wastell, Prashant Bansode, Chaitanya Bijwe


Contents

Use full assembly names when you dynamically load assemblies

If your code supports the dynamic loading of assemblies and you load the assembly by calling Activator.CreateInstance, make sure to refer to the assembly by using its strong name. This prevents your application from accidentally loading a malicious assembly with the same name as a legitimate assembly. The strong name of an assembly contains the public-key token that the assembly was signed with, providing evidence of the author.

The following example shows how to find the strong name for an assembly.


public static StrongName GetStrongName(Assembly assembly)
{
   if(assembly == null)
       throw new ArgumentNullException("assembly");
   AssemblyName assemblyName = assembly.GetName();
       
   // get the public key blob
   byte[] publicKey = assemblyName.GetPublicKey();
   if(publicKey == null || publicKey.Length == 0)
       throw new InvalidOperationException(
           String.Format("{0} is not strongly named", 
           assembly));
   
   StrongNamePublicKeyBlob keyBlob = 
       new StrongNamePublicKeyBlob(publicKey);
   // create the StrongName
   return new StrongName(
       keyBlob, assemblyName.Name, assemblyName.Version);
}


Avoid letting untrusted code or data control run-time assembly load decisions

Avoid letting the user or untrusted code directly control which assemblies or types your code loads. Avoid using user input to derive assembly or type names. These precautions prevent your application from loading a malicious assembly or blindly invoking a method that could be used for malicious purposes.


Avoid letting untrusted code or data control Reflection.Emit

If your application dynamically generates code through the use of Reflection.Emit, do not allow untrusted code or data to influence the code generation. If an attacker can influence the code generation, the attacker could coerce your application into generating malicious code. This is particularly significant if your code uses user-supplied input to generate code dynamically.

There are some scenarios, such as script engine implementation, in which it is necessary to allow untrusted input to drive Reflection.Emit. If your assembly dynamically generates code to perform operations for a caller and the caller operates at a lower trust level, be especially vigilant for security vulnerabilities. Validate any input string used as a string literal in your generated code and escape quotation mark characters to make sure that the caller cannot break out of the literal and inject code. If there is a way that the caller can influence the code generation so that it fails to compile, treat the problem as a potential security vulnerability.


Consider restricting the permissions of dynamically generated assemblies

If you must use user input to help dynamically generate assemblies, you can restrict the permissions available to dynamically created assemblies by using the overload of the AppDomain.DefineDynamicAssembly method, which accepts three permission sets and evidence, as shown in the following example.


public sealed AssemblyBuilder DefineDynamicAssembly(
           AssemblyName name, 
           AssemblyBuilderAccess access, 
           Evidence evidence, 
           PermissionSet requiredPermissions, 
           PermissionSet optionalPermissions, 
           PermissionSet refusedPermissions
);
 

This overload allows you to pass required, optional, and refused permission sets to apply specific security policy to the dynamically created assembly. Passing the evidence forces the CLR to evaluate the permission set for dynamic created code.

Note If you use an overload that does not accept evidence, then the CLR does not evaluate the permission set for the created dynamic assembly. Instead, the permission set granted to the generated code is inherited from the permission set of the assembly that is emitting it.


Only persist dynamically created assemblies if necessary

Where possible, avoid persisting dynamically generated assemblies created with Reflection.Emit. To avoid the risk of the code being called by code external to your application, keep the generated assembly memory resident only and do not persist it.


Use ReflectionOnlyLoadFrom if you only need to inspect code

If you need to load untrusted assemblies to inspect members but not to run code, use the Assembly.ReflectionOnlyLoadFrom method to load the assembly. Reflection-only loading—also known as introspection—allows you to load an assembly to inspect the code's members. This method reduces your attack surface because it does not allow any code from the loaded assembly to run.

Personal tools