[ Team LiB ] |
5.3 Introducing Code-Access SecurityAn important goal of the .NET Framework is to facilitate the development of highly distributed, component-based systems. With the .NET Framework, you can easily create applications that utilize code from different publishers, dynamically loading assemblies from different locations as required. Internet Explorer is an early example of this flexible architecture: downloading and executing .NET controls on demand, and giving the user a rich interface to the Web. Over the coming years, you can expect to see many more .NET applications componentized and delivered "on demand." Traditionally, code executes using the identity, roles, and permissions of the user that runs it. As we discussed in the previous section, role-based security is important for ensuring system security. However, in a connected world where distributed systems and highly mobile code are the order of the day, it is insufficient to base system security decisions solely on the permission granted to the user running an application. Faulty code can damage files to which the user has access, or, worse, malicious code can take advantage of the user's authority to perform all kinds of mischief. A highly trusted user (with extensive system permissions) cannot freely download and run an application from an untrusted source for fear of what the code may do to his system and other systems on his network. Many companies tackle the problem of code security by "locking down" their users' desktops, restricting the applications that people can install and run. This heavy-handed approach requires extensive engineering and support resources to maintain and reduces the utility and flexibility of each user's computer. The .NET Framework includes an important new feature known as code-access security (CAS), which provides fine-grained control over the operations and resources to which managed code has access. With CAS, access is based on the identity of the code, not the user running it. Some examples of operations protected by CAS include:
Other pre-.NET technologies have offered code-level security by differentiating between the identity of code from the user running it. These technologies include Java with its "sandbox" approach and Windows Internet Zones, which restrict the functionality of downloaded controls. However, few of these technologies provide the level of control, flexibility, and extensibility of CAS. 5.3.1 Evidence, Security Policy, and PermissionsThe three key elements of code-access security are evidence, security policy, and permissions. When the runtime loads an assembly, it inspects various characteristics of the assembly (evidence) to determine an identity for the code. Based on a configurable set of rules (security policy), the runtime uses the assembly's evidence as input to a process named policy resolution. The result of policy resolution is a set of protected operations and resources to which the code within the assembly has access (permissions). In the course of execution, code attempts to perform a variety of operations. If the code attempts to perform a protected operation, then the runtime will look at the permissions granted to the assembly containing the code and determine if they include the permission necessary to allow the action to go ahead. Figure 5-2 illustrates the relationship between evidence, security policy, and permissions during policy resolution. Here is a detailed account of each element:
Figure 5-2. Evidence, security policy, and permissions5.3.2 Windows Security and Code-Access SecurityCAS does not replace or circumvent the security provided by the Windows operating system. As shown in Figure 5-3, CAS is effectively another layer of security that managed code must pass through before it can interact with protected system resources, such as the hard disk and the Windows registry. The important difference between CAS and Windows security is that CAS bases security decisions on the identity of the code performing an action, whereas Windows bases security decisions on the identity of the user on whose behalf the code is running. Figure 5-3. Relationship of CAS and OS securityFor example, if a managed application tries to write a file to the hard disk, CAS first determines if the code has the necessary authority to write to the file by evaluating the permissions granted to the assembly when it was loaded. If the code does not have the necessary authority, then the write operation fails and the runtime throws a security exception. On the other hand, if the code does have permission, the runtime interacts with the operating system on behalf of the current user to access the file. If Windows file permissions do not allow the user to write to the specified file, then access is denied and the runtime throws an exception. If the user has write permission, then the file is written. As Figure 5-3 also shows, CAS controls the ability of managed code to call unmanaged (native) code, such as the Win32 APIs. This is important, because when a managed application is allowed to call into unmanaged code, there is no CAS layer to restrict what the unmanaged code can do on behalf of the managed code. Instead of having permissions based on code identity, you are back to the situation where only the permissions of the current user restrict the code's actions. As we discussed at the beginning of this section, this is not sufficient when dealing with mobile code from potentially unknown and untrusted sources. Finally, CAS also controls access to functionality that is internal to the CLR and does not affect operating system resources, such as the ability to create an application domain. We discuss CAS in greater detail in Chapter 6 through Chapter 9. |
[ Team LiB ] |