反射发出中的安全问题Security Issues in Reflection Emit

.NET Framework 提供了三种发出 Microsoft 中间语言 (MSIL) 的方式,每种方式都有其自身的安全问题:The .NET Framework provides three ways to emit Microsoft intermediate language (MSIL), each with its own security issues:

无论采用何种方式生成动态代码,执行生成的代码都需要生成代码使用的类型和方法所需的所有权限。Regardless of the way you generate dynamic code, executing the generated code requires all the permissions that are required by the types and methods the generated code uses.

备注

反射和发出代码所需的权限已在 .NET Framework 的后续版本中更改。The permissions that are required for reflecting on code and emitting code have changed with succeeding releases of the .NET Framework. 请参阅本主题后面的版本信息See Version Information, later in this topic.

动态程序集Dynamic Assemblies

动态程序集是使用 AppDomain.DefineDynamicAssembly 方法的重载创建的。Dynamic assemblies are created by using overloads of the AppDomain.DefineDynamicAssembly method. 此方法的大多数重载在 .NET Framework 4 中已弃用,原因是取消了计算机范围的安全策略。Most overloads of this method are deprecated in the .NET Framework 4, because of the elimination of machine-wide security policy. (请参阅安全更改。)其余的重载可由任意代码执行,而不考虑信任级别。(See Security Changes.) The remaining overloads can be executed by any code, regardless of trust level. 这些重载分为两组:一组重载指定在创建动态程序集时要对该程序集应用的特性的列表,另一组重载则不会进行相应的指定。These overloads fall into two groups: those that specify a list of attributes to apply to the dynamic assembly when it is created, and those that do not. 如果没有通过在创建程序集时应用 SecurityRulesAttribute 属性来指定程序集的透明度模型,则从发出程序集继承透明度模型。If you do not specify the transparency model for the assembly, by applying the SecurityRulesAttribute attribute when you create it, the transparency model is inherited from the emitting assembly.

备注

对于在创建动态程序集之后通过使用 SetCustomAttribute 方法对该程序集应用的特性,只有在将该程序集保存到磁盘并再次加载到内存中之后,这些特性才会起作用。Attributes that you apply to the dynamic assembly after it is created, by using the SetCustomAttribute method, do not take effect until the assembly has been saved to disk and loaded into memory again.

动态程序集中的代码可访问其他程序集中的可见类型和成员。Code in a dynamic assembly can access visible types and members in other assemblies.

备注

动态程序集不使用 ReflectionPermissionFlag.MemberAccessReflectionPermissionFlag.RestrictedMemberAccess 标志,这些标志允许动态方法访问非公共类型和成员。Dynamic assemblies do not use the ReflectionPermissionFlag.MemberAccess and ReflectionPermissionFlag.RestrictedMemberAccess flags that allow dynamic methods to access nonpublic types and members.

瞬态动态程序集在内存中创建,从不保存到磁盘中,因此它们并不需要文件访问权限。Transient dynamic assemblies are created in memory and never saved to disk, so they require no file access permissions. 将动态程序集保存到磁盘需要带有相应标志的 FileIOPermissionSaving a dynamic assembly to disk requires FileIOPermission with the appropriate flags.

从部分受信任的代码生成动态程序集Generating Dynamic Assemblies from Partially Trusted Code

请考虑具有 Internet 权限的程序集可以生成瞬态动态程序集并执行其代码的条件:Consider the conditions in which an assembly with Internet permissions can generate a transient dynamic assembly and execute its code:

  • 动态程序集仅使用其他程序集的公共类型和成员。The dynamic assembly uses only public types and members of other assemblies.

  • 这些类型和成员所需的权限包含在部分受信任的程序集的授予集中。The permissions demanded by those types and members are included in the grant set of the partially trusted assembly.

  • 程序集不保存到磁盘。The assembly is not saved to disk.

  • 不生成调试符号。Debug symbols are not generated. InternetLocalIntranet 权限集未包括必要的权限。)(Internet and LocalIntranet permission sets do not include the necessary permissions.)

匿名托管的动态方法Anonymously Hosted Dynamic Methods

通过使用未指定关联类型或模块的两个 DynamicMethod 构造函数(即 DynamicMethod(String, Type, Type[])DynamicMethod(String, Type, Type[], Boolean))来创建匿名托管的动态方法。Anonymously hosted dynamic methods are created by using the two DynamicMethod constructors that do not specify an associated type or module, DynamicMethod(String, Type, Type[]) and DynamicMethod(String, Type, Type[], Boolean). 这些构造函数将动态方法放到系统提供的完全信任的安全透明的程序集中。These constructors place the dynamic methods in a system-provided, fully trusted, security-transparent assembly. 使用这些构造函数或发出动态方法的代码不需要任何权限。No permissions are required to use these constructors or to emit code for the dynamic methods.

相反,创建一个匿名托管的动态方法后,即捕获调用堆栈。Instead, when an anonymously hosted dynamic method is created, the call stack is captured. 构造该方法时,将根据捕获的调用堆栈执行安全请求。When the method is constructed, security demands are made against the captured call stack.

备注

从概念上来说,在方法的构造过程中执行请求。Conceptually, demands are made during the construction of the method. 即,可在发出各 MSIL 指令时执行请求。That is, demands could be made as each MSIL instruction is emitted. 在当前实现中,当调用 DynamicMethod.CreateDelegate 方法,或调用实时 (JIT) 编译器(如果在没有调用 CreateDelegate 的情况下调用此方法)时将执行所有请求。In the current implementation, all demands are made when the DynamicMethod.CreateDelegate method is called or when the just-in-time (JIT) compiler is invoked, if the method is invoked without calling CreateDelegate.

如果应用程序域允许此操作,则匿名托管的动态方法可跳过 JIT 可见性检查,但受到以下限制:匿名托管的动态方法访问的非公共类型和成员必须位于其授予集等于发出调用堆栈的授予集(或等于发出调用堆栈的授予集的子集)的程序集中。If the application domain permits it, anonymously hosted dynamic methods can skip JIT visibility checks, subject to the following restriction: The nonpublic types and members accessed by an anonymously hosted dynamic method must be in assemblies whose grant sets are equal to, or subsets of, the grant set of the emitting call stack. 如果应用程序域授予带有 ReflectionPermissionFlag.RestrictedMemberAccess 标志的 ReflectionPermission,则启用此跳过 JIT 可见性检查的受限能力。This restricted ability to skip JIT visibility checks is enabled if the application domain grants ReflectionPermission with the ReflectionPermissionFlag.RestrictedMemberAccess flag.

  • 如果你的方法仅使用公共类型和成员,则在构造过程中不需要任何权限。If your method uses only public types and members, no permissions are required during construction.

  • 如果指定应跳过 JIT 可见性检查,则在构造方法时执行的请求包括带有 ReflectionPermissionFlag.RestrictedMemberAccess 标志的 ReflectionPermission,以及包含正在访问的非公共成员的程序集的授予集。If you specify that JIT visibility checks should be skipped, the demand that is made when the method is constructed includes ReflectionPermission with the ReflectionPermissionFlag.RestrictedMemberAccess flag and the grant set of the assembly that contains the nonpublic member that is being accessed.

由于考虑到非公共成员的授予集,因此被授予 ReflectionPermissionFlag.RestrictedMemberAccess 的部分受信任代码无法通过执行受信任程序集的非公共成员来提升其特权。Because the grant set of the nonpublic member is taken into consideration, partially trusted code that has been granted ReflectionPermissionFlag.RestrictedMemberAccess cannot elevate its privileges by executing nonpublic members of trusted assemblies.

与任何其他发出的代码一样,执行动态方法需要动态方法使用的方法所需的所有权限。As with any other emitted code, executing the dynamic method requires whatever permissions are demanded by the methods the dynamic method uses.

托管匿名托管的动态方法的系统程序集使用 SecurityRuleSet.Level1 透明度模型,这是在 .NET Framework 4 之前的 .NET Framework 中使用的透明度模型。The system assembly that hosts anonymously-hosted dynamic methods uses the SecurityRuleSet.Level1 transparency model, which is the transparency model that was used in the .NET Framework before the .NET Framework 4.

有关更多信息,请参见 DynamicMethod 类。For more information, see the DynamicMethod class.

从部分受信任的代码中生成匿名托管的动态方法Generating Anonymously Hosted Dynamic Methods from Partially Trusted Code

请考虑具有 Internet 权限的程序集可以生成匿名托管的动态方法并执行该方法的条件:Consider the conditions in which an assembly with Internet permissions can generate an anonymously hosted dynamic method and execute it:

  • 动态方法仅使用公共类型和成员。The dynamic method uses only public types and members. 如果动态方法的授予集包含 ReflectionPermissionFlag.RestrictedMemberAccess,则动态方法可以使用任何其授予集等于发出程序集的授予集(或等于发出程序集的授予集的子集)的程序集的非公共类型和成员。If its grant set includes ReflectionPermissionFlag.RestrictedMemberAccess, it can use nonpublic types and members of any assembly whose grant set is equal to, or a subset of, the grant set of the emitting assembly.

  • 动态方法使用的所有类型和成员所需的权限包含在部分受信任的程序集的授予集中。The permissions that are required by all the types and members used by the dynamic method are included in the grant set of the partially trusted assembly.

备注

动态方法不支持调试符号。Dynamic methods do not support debug symbols.

与现有程序集关联的动态方法Dynamic Methods Associated with Existing Assemblies

若要将动态方法与现有程序集中的某一类型或模块关联,请使用指定关联类型或模块的任一 DynamicMethod 构造函数。To associate a dynamic method with a type or module in an existing assembly, use any of the DynamicMethod constructors that specify the associated type or module. 调用这些构造函数所需的权限各不相同,这是因为将动态方法与现有类型或模块关联会授予该动态方法访问非公共类型和成员的权限:The permissions that are required to call these constructors vary, because associating a dynamic method with an existing type or module gives the dynamic method access to nonpublic types and members:

  • 与某一类型关联的动态方法具有对该类型的所有成员(甚至私有成员)以及包含此关联类型的程序集中的所有内部类型和成员的访问权限。A dynamic method that is associated with a type has access to all members of that type, even private members, and to all internal types and members in the assembly that contains the associated type.

  • 与某一模块相关联的态方法具有对该模块中的所有 internal 类型和成员(在 Visual Basic 中为 Friend,在公共语言运行时元数据中为 assembly)的访问权限。A dynamic method that is associated with a module has access to all the internal types and members (Friend in Visual Basic, assembly in common language runtime metadata) in the module.

此外,你可以使用一个构造函数来指定跳过 JIT 编译器的可见性检查的能力。In addition, you can use a constructor that specifies the ability to skip the visibility checks of the JIT compiler. 执行此操作可向动态方法授予对所有程序集中的所有类型和成员的访问权限,而无论访问级别如何。Doing so gives your dynamic method access to all types and members in all assemblies, regardless of access level.

构造函数所需的权限取决于你决定向动态方法授予多少访问权限:The permissions demanded by the constructor depend on how much access you decide to give your dynamic method:

虽然此列表中的项是用发出程序集的授予集来描述的,但是请记住,请求是根据完整的调用堆栈(包括应用程序域边界)来执行的。Although the items in this list are described in terms of the grant set of the emitting assembly, remember that the demands are made against the full call stack, including the application domain boundary.

有关更多信息,请参见 DynamicMethod 类。For more information, see the DynamicMethod class.

从部分受信任的代码生成动态方法Generating Dynamic Methods from Partially Trusted Code

备注

从部分受信任的代码生成动态方法的推荐方式是使用匿名托管的动态方法The recommended way to generate dynamic methods from partially trusted code is to use anonymously hosted dynamic methods.

请考虑具有 Internet 权限的程序集可以生成并执行动态方法的条件:Consider the conditions in which an assembly with Internet permissions can generate a dynamic method and execute it:

  • 动态方法要么与发出它的模块或类型相关联,要么其授予集中包含 ReflectionPermissionFlag.RestrictedMemberAccess,并且该方法与其授予集等于发出程序集的授予集(或者等于发出程序集的授予集的子集)的程序集中的模块关联。Either the dynamic method is associated with the module or type that emits it, or its grant set includes ReflectionPermissionFlag.RestrictedMemberAccess and it is associated with a module in an assembly whose grant set is equal to, or a subset of, the grant set of the emitting assembly.

  • 动态方法仅使用公共类型和成员。The dynamic method uses only public types and members. 如果动态方法的授予集包含 ReflectionPermissionFlag.RestrictedMemberAccess,并且该方法与其授予集等于发出程序集的授予集(或者等于发出程序集的授予集的子集)的程序集中的模块关联,那么该方法可使用关联模块中标记为 internal 的类型和成员(在 Visual Basic 中为 Friend,在公共语言运行时元数据中为 assembly)。If its grant set includes ReflectionPermissionFlag.RestrictedMemberAccess and it is associated with a module in an assembly whose grant set is equal to, or a subset of, the grant set of the emitting assembly, it can use types and members marked internal (Friend in Visual Basic, assembly in common language runtime metadata) in the associated module.

  • 动态方法使用的所有类型和成员所需的权限包含在部分受信任的程序集的授予集中。The permissions demanded by all the types and members used by the dynamic method are included in the grant set of the partially trusted assembly.

  • 动态方法不会跳过 JIT 可见性检查。The dynamic method does not skip JIT visibility checks.

备注

动态方法不支持调试符号。Dynamic methods do not support debug symbols.

版本信息Version Information

从 .NET Framework 4 开始,已取消计算机范围的安全策略,并且安全透明度已成为默认的强制机制。Starting with the .NET Framework 4, machine-wide security policy is eliminated and security transparency becomes the default enforcement mechanism. 请参阅安全更改See Security Changes.

从 .NET Framework 2.0 Service Pack 1 开始,在发出动态程序集和动态方法时不再需要带有 ReflectionPermissionFlag.ReflectionEmit 标志的 ReflectionPermissionStarting with the .NET Framework 2.0 Service Pack 1, ReflectionPermission with the ReflectionPermissionFlag.ReflectionEmit flag is no longer required when emitting dynamic assemblies and dynamic methods. 所有早期版本的 .NET Framework 都需要此标志。This flag is required in all earlier versions of the .NET Framework.

备注

默认情况下,带有 ReflectionPermissionFlag.ReflectionEmit 标志的 ReflectionPermission 包含在 FullTrustLocalIntranet 命名权限集中,而不是在 Internet 权限集中。ReflectionPermission with the ReflectionPermissionFlag.ReflectionEmit flag is included by default in the FullTrust and LocalIntranet named permission sets, but not in the Internet permission set. 因此,在 .NET Framework 的早期版本中,仅当库执行 ReflectionEmitAssert 时才能与 Internet 权限一起使用。Therefore, in earlier versions of the .NET Framework, a library can be used with Internet permissions only if it executes an Assert for ReflectionEmit. 这种库需要进行仔细的安全检查,因为编码错误可能会导致安全漏洞。Such libraries require careful security review because coding errors could result in security holes. .NET Framework 2.0 SP1 允许以部分信任形式发出代码而无需发出任何安全请求,因为生成代码本身不是一项特权操作。The .NET Framework 2.0 SP1 allows code to be emitted in partial trust scenarios without issuing any security demands, because generating code is not inherently a privileged operation. 也就是说,生成的代码不会具有比发出它的程序集更多的权限。That is, the generated code has no more permissions than the assembly that emits it. 这使得发出代码的库是安全透明的,且不再需要断言 ReflectionEmit,这简化了编写安全库任务。This allows libraries that emit code to be security transparent and removes the need to assert ReflectionEmit, which simplifies the task of writing a secure library.

此外,.NET Framework 2.0 SP1 引入了 ReflectionPermissionFlag.RestrictedMemberAccess 标志,用于从部分受信任的动态方法访问非公共类型和成员。In addition, the .NET Framework 2.0 SP1 introduces the ReflectionPermissionFlag.RestrictedMemberAccess flag for accessing nonpublic types and members from partially trusted dynamic methods. .NET Framework 的早期版本需要访问非公共类型和成员的动态方法的 ReflectionPermissionFlag.MemberAccess 标志;绝不会将该权限授予部分受信任的代码。Earlier versions of the .NET Framework require the ReflectionPermissionFlag.MemberAccess flag for dynamic methods that access nonpublic types and members; this is a permission that should never be granted to partially trusted code.

最后,.NET Framework 2.0 SP1 引入了匿名托管的方法。Finally, the .NET Framework 2.0 SP1 introduces anonymously hosted methods.

获取有关类型和成员的信息Obtaining Information on Types and Members

从 .NET Framework 2.0 开始,获取有关非公共类型和成员信息不再需要任何权限。Starting with the .NET Framework 2.0, no permissions are required to obtain information about nonpublic types and members. 使用反射可获取发出动态方法所需的信息。Reflection is used to obtain information needed to emit dynamic methods. 例如,使用 MethodInfo 对象发出方法调用。For example, MethodInfo objects are used to emit method calls. .NET Framework 的早期版本需要使用带有 ReflectionPermissionFlag.TypeInformation 标志的 ReflectionPermissionEarlier versions of the .NET Framework require ReflectionPermission with the ReflectionPermissionFlag.TypeInformation flag. 有关详细信息,请参阅反射的安全注意事项For more information, see Security Considerations for Reflection.

请参阅See also