Code Access Security


Code access security is a feature of .NET that manages code, dependent on your level of trust. If the CLR trusts the code enough to allow it to run, it will begin executing the code. Depending on the permissions given to the assembly, however, it might run within a restricted environment. If the code is not trusted enough to run, or if it runs but then attempts to perform an action for which it does not have the relevant permissions, a security exception (of type SecurityException or a subclass of it) is thrown. The code access security system means that you can stop malicious code running, but you can also allow code to run within a protected environment where you are confident that it cannot do any damage.

For example, if a user attempted to run an application that attempted to execute code downloaded from the Internet, the default security policy would raise an exception and the application would fail to start. Similarly, if the user ran an application from a network drive it would begin executing, but if the application then attempted to access a file on the local drive, the runtime would raise an exception and, depending on the error handling in the application, it would either gracefully degrade or exit.

For most applications, .NET's code access security is a significant benefit, but one that sits at the back of the room quietly helping. It provides high levels of protection from malicious code, but generally, youneedn't get involved. However, one area you will be involved in is the management of security policy, and this is especially the case when desktop applications are configured to trust code from the locations of software suppliers delivering applications to you.

Another area where code access security becomes very important is the building of an application that includes an element whose security you want to control closely. For example, if there is a database within your organization containing extremely sensitive data, you would use code access security to state what code is allowed to access that database, and what code must not access it.

It is important to realize that code access security is about protecting resources (local drive, network, and user interface) from malicious code; it is not primarily a tool for protecting software from users. For security in relation to users, you will generally use the built-in Windows user security subsystem, or make use of .NET role-based security, which is discussed later in this chapter.

Code access security is based on two high-level concepts: code groups and permissions. Let's look at them before we start since they both form the foundations of the sections that follow:

  • Code groups bring together code with similar characteristics, although the most important property is usually where the code came from. Two examples for code groups are Internet and Intranet. The group Internet defines code that is sourced from the Internet, and the group Intranet defines code sourced from the LAN. The information used to place assemblies into code groups is called evidence. Other evidence is collected by the CLR, including the publisher of the code, the strong name, and (where applicable) the URI from which it was downloaded. Code groups are arranged in a hierarchy, and assemblies are nearly always matched to several code groups. The code group at the root of the hierarchy is called All Code and contains all other code groups. The hierarchy is used for deciding which code groups an assembly belongs to; if an assembly does not provide evidence that matches it to a group in the tree, no attempt is made to match it to code groups below.

  • Permissions are the actions you allow each code group to perform. For example, permissions include "able to access the user interface" and "able to access local storage." The system administrator usually manages the permissions at the enterprise, machine, and user levels.

The Virtual Execution System within the CLR loads and runs programs. It provides the functionality required to execute managed code and uses assembly metadata to connect modules together at runtime. When the VES loads an assembly, it matches the assembly to one or more of a number of code groups. Each code group is assigned to one or more permissions that specify what actions assemblies can do in that code group. For example, if the MyComputer code group is assigned the permission FileIOPermission, this means that assemblies from the local machine can read and write to the local file system.

Code Groups

Code groups have an entry requirement called membership condition. For an assembly to be filed into a code group, it must match the group's membership condition. Membership conditions include "the assembly is from the site www.microsoft.com" or "the publisher of this software is Microsoft Corporation."

Each code group has one, and only one, membership condition. The following list provides the types of code group membership conditions available in .NET:

  • Zone — The region from which the code originated.

  • Site — The Web site from which the code originated.

  • Strong name — A unique, verifiable name for the code. Strong names are discussed in Chapter 15, "Assemblies."

  • Publisher — The publisher of the code.

  • URL — The specific location from which the code originated.

  • Hash value — The hash value for the assembly.

  • Skip verification — This condition requests that it bypasses code verification checks. Code verification ensures the code accesses types in a well-defined and acceptable way. The runtime cannot enforce security on code that is not type safe.

  • Application directory — The location of the assembly within the application.

  • All code — All code fulfills this condition.

  • Custom — A user-specified condition.

The first, and most commonly used, type of membership condition is the Zone condition. A zone is the region of origin of a piece of code and refers to one of the following: MyComputer, Internet, Intranet, Trusted, or Untrusted. These zones can be managed by using the security options in Internet Explorer. Zones are discussed in more detail in the section "Managing Security Policies." Although the settings are managed within Internet Explorer, they apply to the entire machine. Clearly, these configuration options are not available in non-Microsoft browsers and, in fact, in-page controls written using the .NET Framework will not work in browsers other than Internet Explorer.

Code groups are arranged hierarchically with the All Code membership condition at the root (see Figure 16-1). You can see that each code group has a single membership condition and specifies the permissions that the code group has been granted. Note that if an assembly does not match the membership condition in a code group, the CLR does not attempt to match code groups below it.

image from book
Figure 16-1

caspol.exe — The Code Access Security Policy tool

This section spends a good deal of time looking at the command-line Code Access Security Policy tool. To get a list of options for the tool, just type the following at the command prompt:

 caspol.exe -? 

To send the output to a text file, use:

 caspol.exe > output.txt 

.NET also includes a snap-in for the Microsoft Management Console to manage code access security. However, this discussion is restricted to the command-line utility, because the examples are easier to follow, and you'll also be in a position to create scripts to alter the security policy, which is very useful when applying policies to large numbers of machines.

Let's look at the code groups on a machine using caspol.exe. The output of the command lists the hierarchical structure of the code groups on the machine, and next to each group there is a description of the code group. Type this command:

 caspol.exe –listdescription 

Alternatively, the -listdescription parameter has a shortcut: -ld. You will see something like this:

Microsoft (R) .NET Framework CasPol 2.0.50727.7 Copyright (C) Microsoft Corporation. All rights reserved. Security is ON Execution checking is ON Policy change prompt is ON Level = Machine Full Trust Assemblies: 1. All_Code: Code group grants no permissions and forms the root of the code  group tree.    1.1. My_Computer_Zone: Code group grants full trust to all code originating          on the local computer       1.1.1. Microsoft_Strong_Name: Code group grants full trust to code signed              with the Microsoft strong name.       1.1.2. ECMA_Strong_Name: Code group grants full trust to code signed with              the ECMA strong name.    1.2. LocalIntranet_Zone: Code group grants the intranet permission set to          code from the intranet zone. This permission set grants intranet code                 the right to use isolated storage, full UI access, some capability to do         reflection, and limited access to environment variables.       1.2.1. Intranet_Same_Site_Access: All intranet code gets the right to              connect back to the site of its origin.       1.2.2. Intranet_Same_Directory_Access: All intranet code gets the right to              read from its install directory.    1.3. Internet_Zone: Code group grants code from the Internet zone the          Internet permission set. This permission set grants Internet code the right         to use isolated storage and limited UI access.       1.3.1. Internet_Same_Site_Access: All Internet code gets the right to              connect back to the site of its origin.    1.4. Restricted_Zone: Code coming from a restricted zone does not receive any         permissions.    1.5. Trusted_Zone: Code from a trusted zone is granted the Internet          permission set. This permission set grants the right to use isolated            storage and limited UI access.       1.5.1. Trusted_Same_Site_Access: All Trusted Code gets the right to              connect back to the site of its origin.    1.6  Application_Security_Manager: Code group grants trust to ClickOnce               applications.       1.6.1. Intranet_Same_Site_Access: All intranet code gets the right              to connect back to the site of its origin.       1.6.2. Intranet_Same_Directory_Access: All intranet code gets the              right to read from its install directory. Success

The .NET security subsystem ensures that code from each code group is allowed to do only certain things. For example, code from the Internet zone will, by default, have much stricter limits than code from the local drive. Code from the local drive is normally granted access to data stored on the local drive, but assemblies from the Internet are not granted this permission by default.

Using caspol and its equivalent in the Microsoft Management Console, you can specify what level of trust you have for each code access group, as well as managing code groups and permissions in a more granular fashion.

Let's take another look at the code access groups, but this time in a slightly more compact view. Make sure you're logged in as a local administrator, go to a command prompt, and type this command:

 caspol.exe –listgroups 

You will see something like this:

Microsoft (R) .NET Framework CasPol 2.0.50727.7 Copyright (C) Microsoft Corporation. All rights reserved. Security is ON Execution checking is ON Policy change prompt is ON Level = Machine Code Groups: 1.  All code: Nothing    1.1.  Zone - MyComputer: FullTrust       1.1.1.  StrongName - 00240000048000009400000006020000002400005253413100040 0000100010007D1FA57C4AED9F0A32E84AA0FAEFD0DE9E8FD6AEC8F87FB03766C834C99921EB23BE 79AD9D5DCC1DD9AD236132102900B723CF980957FC4E177108FC607774F29E8320E92EA05ECE4E82 1C0A5EFE8F1645C4C0C93C1AB99285D622CAA652C1DFAD63D745D6F2DE5F17E5EAF0FC4963D261C8 A12436518206DC093344D5AD293: FullTrust       1.1.2.  StrongName - 00000000000000000400000000000000: FullTrust    1.2.  Zone - Intranet: LocalIntranet       1.2.1.  All code: Same site Web.       1.2.2.  All code: Same directory FileIO – 'Read, PathDiscovery'    1.3.  Zone - Internet: Internet       1.3.1.  All code: Same site Web.    1.4.  Zone - Untrusted: Nothing    1.5.  Zone - Trusted: Internet       1.5.1.  All code: Same site Web. Success

You'll notice that near the start of the output it says Security is ON. Later in the chapter you see that it can be turned off and then turned on again.

The Execution Checking setting is on by default, which means that all assemblies must be granted the permission to execute before they can run. If execution checking is turned off using caspol (caspol.exe –execution on|off), assemblies that do not have the permission to run can execute, although they might cause security exceptions if they attempt to act contrary to the security policy later in their execution.

The Policy change prompt option specifies whether you see an "Are you sure" warning message when you attempt to alter the security policy.

As code is broken down into these groups, you can manage security at a more granular level, and apply full trust to a much smaller percentage of code. Note that each group has a label (for example, 1.2). These labels are auto-generated by .NET, and can differ between machines. Generally, security is not managed for each assembly, but for using a code group instead.

When a machine has several side-by-side installations of .NET, the copy of caspol.exe that you run will only alter the security policy for the installation of .NET with which it is associated.

Viewing an assembly's code groups

Assemblies are matched to code groups dependent on the membership conditions they match. If you go back to the code-groups example and load an assembly from the https://intranet/ Web site, it would match the code groups shown in Figure 16-2. The assembly is a member of the root code group (All Code); because it came from the local network it is also a member of the Intranet code group. However, because it was loaded from the specific site https://intranet, it is also granted FullTrust, which means it can run unrestricted.

image from book
Figure 16-2

You can easily view the code groups that an assembly is a member of using this command:

 caspol.exe –resolvegroup assembly.dll 

Running this command on an assembly on the local drive produces the following output:

Microsoft (R) .NET Framework CasPol 2.0.50727.7 Copyright (C) Microsoft Corporation. All rights reserved. Level = Enterprise Code Groups: 1.  All code: FullTrust Level = Machine Code Groups: 1.  All code: Nothing    1.1.  Zone - MyComputer: FullTrust Level = User Code Groups: 1.  All code: FullTrust Success

You'll notice that code groups are listed on three levels — Enterprise, Machine, and User. For now, stay focused on the machine level. If you are curious about the relationship between the three, the effective permission given to an assembly is the intersection of the permissions from the three levels. For example, if you remove the FullTrust permission from the Internet zone at the enterprise-level policy, all permissions are revoked for code from the Internet zone, and the settings of the other two levels become irrelevant.

Now use this command once more with the same assembly to read the code groups. However, this time the assembly is accessed from a Web server using the HTTP protocol. You can see the assembly is a member of different groups that have much more restrictive permissions:

 caspol.exe –resolvegroup http://server/assembly.dll Microsoft (R) .NET Framework CasPol 2.0.50727.7 Copyright (C) Microsoft Corporation. All rights reserved. Level = Enterprise Code Groups: 1.  All code: FullTrust Level = Machine Code Groups: 1.  All code: Nothing    1.1.  Zone - Internet: Internet       1.1.1.  All code: Same site Web. Level = User Code Groups: 1.  All code: FullTrust Success

The assembly grants the Internet and the Same Site Web permissions. The intersection of the permissions allows the code limited UI access. It also permits the code to establish connections to the site it originated from.

The following section takes a closer look at permissions.

Code Access Permissions and Permissions Sets

Imagine yourself administering security policy on a network of desktop machines in a large enterprise scenario. In this environment it's immensely useful for the CLR to collect evidence information on code before the code is allowed to execute. Likewise, you as the administrator must have the opportunity to control what code is allowed on the several hundred machines you manage once the CLR has identified its origin. This is where permissions start to act.

After an assembly has been matched to code groups, the CLR looks at the security policy to calculate the permissions it grants to an assembly. When managing permissions in Windows you generally don't want to apply permissions to users, but you apply permissions to user groups instead. This is also true with assemblies; permissions are applied to code groups rather than to individual assemblies, which makes the management of security policy in .NET a much easier task.

The security policy specifies what actions assemblies are allowed to perform in a code group. The following list shows a few of the code access permissions provided by the CLR; as you can see, you have big control of what code is permitted to do or not:

  • DirectoryServicesPermission controls the ability to access Active Directory through the System.DirectoryServices classes.

  • DnsPermission controls the ability to use the TCP/IP Domain Name System (DNS).

  • EnvironmentPermission controls the ability to read and write environment variables.

  • EventLogPermission controls the ability to read and write to the event log.

  • FileDialogPermission controls the ability to access files that have been selected by the user in the Open dialog box. This permission is commonly used when FileIOPermission is not granted to allow limited access to files.

  • FileIOPermission controls the ability to work with files (reading, writing, and appending to file, as well as creating and altering folders and accessing).

  • IsolatedStorageFilePermission controls the ability to access private virtual file systems.

  • IsolatedStoragePermission controls the ability to access isolated storage; storage that is associated with an individual user and with some aspect of the code's identity. Isolated storage is discussed in Chapter 34, "Manipulating Files and the Registry."

  • MessageQueuePermission controls the ability to use message queues through the Microsoft Message Queue.

  • OleDbPermission controls the ability to access databases with OLE DB providers.

  • PerformanceCounterPermission controls the ability to make use of performance counters.

  • PrintingPermission controls the ability to print.

  • ReflectionPermission controls the ability to discover information about a type at runtime using System.Reflection.

  • RegistryPermission controls the ability to read, write, create, or delete registry keys and values.

  • SecurityPermission controls the ability to execute, assert permissions, call into unmanaged code, skip verification, and other rights.

  • ServiceControllerPermission controls the ability to control Windows services.

  • SocketPermission controls the ability to make or accept TCP/IP connections on a network transport address.

  • SQLClientPermission controls the ability to access SQL Server databases with the .NET data provider for SQL Server.

  • UIPermission controls the ability to access the user interface.

  • WebPermission controls the ability to make or accept connections to or from the Web.

With each of these permission classes, it is often possible to specify an even deeper level of granularity. Later in this chapter you see an example of requesting not just file access but a specific level of file access.

In terms of best practice, you are well advised to ensure any attempts to make use of resources require that permissions are enclosed within try/catch error handling blocks, so that your application degrades gracefully should it be running under restricted permissions. The design of your application should specify how your application should act under these circumstances. Do not assume that it will be running under the same security policy under which it has been developed. For example, if your application cannot access the local drive, should it exit or operate in an alternative fashion?

An assembly is associated with several code groups; the effective permission of an assembly within the security policy is the union of all permissions from all the code groups to which it belongs. That is, each code group that an assembly matches extends what it is allowed to do. Note that code groups further down the tree are often assigned more relaxed permissions than those higher up.

Another set of permissions is assigned by the CLR on the basis of the identity of the code, which cannot be granted. These permissions relate to the evidence the CLR has collated about the assembly and are called Identity Permissions. Here are the names of the classes for the identity permissions:

  • PublisherIdentityPermission refers to the software publisher's digital signature.

  • SiteIdentityPermission refers to the name of the Web site from which the code originated.

  • StrongNameIdentityPermission refers to the assembly's strong name.

  • URLIdentityPermission refers to the URL from which the code came (including the protocol, for example, https://).

  • ZoneIdentityPermission refers to the zone from which the assembly originates.

By assigning the permission to code groups, there's no need to deal with every single permission. Instead, the permissions are applied in blocks, which is why .NET has the concept of permission sets. These are lists of code access permissions grouped into a named set. The following list explains the named permission sets you get out of the box:

  • FullTrust means no permission restrictions.

  • SkipVerification means that verification is not done.

  • Execution grants the ability to run, but not to access any protected resources.

  • Nothing grants no permissions and prevents the code from executing.

  • LocalIntranet specifies the default policy for the local intranet, a subset of the full set of permissions. For example, file IO is restricted to read access on the share where the assembly originates.

  • Internet specifies the default policy for code of unknown origin. This is the most restrictive policy listed. For example, code executing in this permission set has no file IO capability, cannot read or write event logs, and cannot read or write environment variables.

  • Everything grants all the permissions that are listed under this set, except the permission to skip code verification. The administrator can alter any of the permissions in this permission set. This is useful where the default policy needs to be tighter.

    Note

    Note that of these you can only change the definitions of the Everything permission set — the other sets are fixed and cannot be changed.

Identity permissions cannot be included in permission sets because the CLR is the only body able to grant identity permissions to code. For example, if a piece of code is from a specific publisher, it would make little sense for the administrator to assign the identity permissions associated with another publisher. The CLR grants identity permissions where necessary, and if you want you can use them.

Viewing an assembly's permissions

Imagine using a Microsoft application where you use a feature that you have not used before. The application does not have a copy of the code stored locally, so the code is requested from the Internet and downloaded into the Download Assembly Cache. Figure 16-3 illustrates what an assembly's code group membership might look like with code from the Internet published by a named organization that has signed the assembly with a certificate.

image from book
Figure 16-3

Although the All Code and Internet code groups bring only limited permissions according to the policy in this example, membership of the code group in the bottom right-hand corner grants the assembly the FullTrust permission. The overall effective permission is the union of permissions across the matching code groups. When the permissions are merged this way, the effective permission is that of all permissions granted, that is, each code group to which an assembly belongs brings additional permissions.

Just as you can check what code groups an assembly belongs to, it is also possible to look at the permissions assigned to the code groups. Doing this you'll see not only the code access permissions (what the code is allowed to do), but also the code identity permissions that will give you access to the evidence the code presented to the runtime. To see the permissions for an assembly's code groups, use a command like this:

 caspol.exe –resolveperm assembly.dll 

Try this on an assembly and look at the granted code access and identity permissions when the assembly is accessed over a local intranet. If you type the following command, you will see the code access permissions and then the three identity permissions at the end:

 caspol.exe –resolveperm http://somehost/assembly.dll Microsoft (R) .NET Framework CasPol 2.0.50727.7 Copyright (C) Microsoft Corporation. All rights reserved. Resolving permissions for level = Enterprise Resolving permissions for level = Machine Resolving permissions for level = User Grant = <PermissionSet     version="1"> <IPermission  Version="1" Read="Username"/> <IPermission        version="1" Unrestricted="true"/> <IPermission  version="1"       Allowed="AssemblyIsolationByUser"       UserQuota="9223372036854775807" Expiry="9223372036854775807"       Permanent="True"/> <IPermission 2.0.0.0, Culture=neutral,       PublicKeyToken= b77a5c561934e089" Version="1"       Flags="ReflectionEmit" /> <IPermission  version="1"       Flags="Assertion, Execution, BindingRedirects"/> <IPermission  version="1"       Unrestricted="true" /> <IPermission  version="1"       Site="somehost" /> <IPermission  version="1"       Url="http://somehost/assembly.dll" /> <IPermission  version="1"       Zone="Intranet" /> <IPermission  version="1"       Unrestricted="true" /> <IPermission  version="1"       Level="Restricted" /> <IPermission  version="1"       Level="DefaultPrinting" /> <IPermission  version="1">       <ConnectAccess>          <URI uri="(https|http)://somehost/.*[/]?"/>       </ConnectAccess>    </IPermission> </PermissionSet> Success

The output shows each of the permissions in XML, including the class defining the permission, the assembly containing the class, the permission version, and an encryption token. The output suggests that it is possible for you to create your own permissions. You can also see that each of the identity permissions includes more detailed information on, for example, the UrlIdentityPermission class, which provides access to the URL from which the code originated.

Note how at the start of the output, caspol.exe resolved the permissions at the enterprise, machine, and user levels and then listed the effective granted permissions, which is worth a closer look.

Policy Levels: Machine, User, and Enterprise

Up to now, you have dealt with security in the context of a single machine. It's often necessary to specify security policies for specific users or for an entire organization, and that is why .NET provides not one but three policy levels:

  • Machine

  • Enterprise

  • User

The code group levels are independently managed and exist in parallel, as shown in Figure 16-4.

image from book
Figure 16-4

If there are three security policies, how do you know which one applies? The effective permission is the intersection of the permissions from these three levels. Each of the three levels has the ability to veto the permissions allowed by another — this is really good news for administrators because their settings will override user settings.

To work with code groups and permissions on the user or enterprise levels using caspol.exe, add either the -enterprise or -user argument to change the command's mode. caspol.exe works at the machine level by default and that's how you've been using it until now. Use the following command to see the code groups listing at the user level:

 caspol.exe –user –listgroups 

The output of the command on a default installation looks like this:

Security is ON Execution checking is ON Policy change prompt is ON Level = User Code Groups: 1.  All code: FullTrust Success

Now run the same command but this time with the code groups at the enterprise level:

 caspol.exe –enterprise –listgroups 

The output of the command looks like this:

Security is ON Execution checking is ON Policy change prompt is ON Level = Enterprise Code Groups: 1.  All code: FullTrust Success

As you can see, by default, both the user level and the enterprise level are configured to allow FullTrust for the single code group All Code. The result of this is that the default setting for .NET security places no restrictions at the enterprise or user levels, and the enforced policy is dictated solely by the machine- level policy. For example, if you were to assign a more restrictive permission or permission set to either the enterprise or user levels than FullTrust, those restrictions would restrict the overall permissions, and probably override permissions at the machine level. The effective permissions are intersected. If you want to apply FullTrust to a code group, this permission must be assigned to the code group on each of the three policy levels.

When you run caspol.exe as an administrator, it defaults to the machine level, but if you log out and log back in as a user who is not in the Administrator user group, caspol.exe will default to the user level instead. In addition, caspol.exe will not allow you to alter the security policy in a way that renders the caspol.exe utility itself inoperable.

You've had a high-level look at the security architecture in .NET; you now learn how to realize code access security features programmatically.




Professional C# 2005
Pro Visual C++ 2005 for C# Developers
ISBN: 1590596080
EAN: 2147483647
Year: 2005
Pages: 351
Authors: Dean C. Wills

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net