Securing Against Harmful Assemblies

The SSCLI supports Code Access Security (CAS) , which is a component-aware approach to security that extends traditional OS security concepts. The goal for the SSCLI is to provide a level playing field for the components themselves, to enable code from many sources to be combined into applications. Since programs run under the control of the execution engine, and since component code is verified when it is JIT compiled, it is possible for the CLI execution engine to intervene when components misbehave. Because this is possible, the runtime enforcement mechanisms of code access security have real teeth. They would not be possible without managed execution as their foundation.

Code access security combines permissions with evidence and policy. There are two parts to CAS: the assembly load phase and the runtime enforcement phase. We will talk briefly about the load phase at this point and defer the discussion of how runtime enforcement is achieved until Chapter 6.

Permissions represent specific capabilities, such as the ability to read a file. Permissions are used in permission grants and permission demands , which are runtime actions that are tracked and enforced by the CAS service within the execution engine. A permission grant (henceforth referred to as just a “grant”) is an authorization based on some combination of policy and evidence; a demand is a check for the corresponding grant.

Within an assembly, permissions may be associated with resources, code identity, or user identity, and are granted to code on a per-assembly basis rather than on a per-user or per-process basis. Permissions are applied to code either declaratively, in which case custom attributes specify behavior in conjunction with policy, or imperatively, in which case code is written to manipulate the CAS service directly to specify behavior. There are numerous resource permissions built into the SSCLI, such as the FileIOPermission, the EnvironmentPermission, and the UIPermission. There is also support for code identity permissions based on strongname. Finally, there is very basic skeletal support for generic user identities and authorization, as well as role-based identities. To see how these are implemented and to learn about others, look in the sscli/clr/src/bcl/system/security/permissions directory.

The programmer responsible for an assembly provides the nucleus around which the CAS service operates. In the assembly’s code, either as attributes or as direct API calls, security requirements are specified through grants and demands. On top of this nucleus, the user or administrator who is responsible for the runtime well-being of its applications must also have a say in specifying security requirements and behaviors. In the CAS service, this is referred to as policy and is implemented as a set of XML configuration files (much like the versioning configurations that we examined earlier in this chapter).

Evidence is information about the assembly to be loaded and is used by the CLI in conjunction with policy to make binding decisions about which permissions to grant and which to deny. Evidence is implicitly trusted information, and the execution engine has built-in support for certain types of evidence, such as digital signatures or the directory from which an assembly is loaded. Assemblies can also provide additional evidence in the form of permission set requests , which are useful because they allow programmers who create components to provide evidence on their own behalf. The evidence to support permission set requests can be put into an assembly in serialized form, to be deserialized when the CAS engine prepares to audit the evidence at runtime.

An assembly’s set of grants is determined by combining evidence, assembly demands, and policy at runtime. In order for this to be secure, a careful loading sequence must be followed, during which evidence and policy are created in preparation for their interpretation. One of the great advantages of the CLI’s data-driven model is that the persistent representation of assemblies can accommodate this carefully specified mechanism in a way that allows new or custom data to be added after the fact. Evidence is an example of the sort of annotation for which this capability is important, since the runtime conditions under which a component is used may change drastically over the years.

Evidence attached to code is itself represented as components, and is extensible. Of course, custom evidence will be taken into consideration only if the policy being applied looks for it during the loading process, but the execution engine has been designed to allow for this kind of extension. Assemblies can contain custom evidence directly as serialized data or can provide it programmatically.

Get Shared Source CLI Essentials now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.