Code Access Security

 
Chapter 23 - .NET Security
bySimon Robinsonet al.
Wrox Press 2002
  

Code access security is a feature of .NET that manages code dependent on our level trust of it. If the CLR trusts the code enough to allow it to run, it will begin executing the code. Depending on the permissions provided to the assembly, however, it may 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 we can stop malicious code running, but we can also allow code to run within a protected environment where we are confident 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. In a similar way, 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, 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 us out. It provides high levels of protection from malicious code, but generally , we do not need to get involved. However, one area we will be involved in is the management of security policy, and this is especially true when configuring desktops to trust code from the locations of software suppliers who are delivering applications to us.

Another area where code access security is more important is where we are building an application that includes an element whose security we want to closely control. 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 how code access security is about protecting resources (local drive, network, 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 Windows 2000's built-in user security subsystem, or make use of .NET's role-based security, which we will look at later in the chapter.

Code access security is based upon two high-level concepts; Code Groups , and Permissions . Let's look at these before we start as they form the foundations of what follows :

  • Code Groups bring together code with similar characteristics, although the most important property is usually where the code came from. For example, code groups include "Internet" (code sourced from the Internet) and "Intranet" (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 in 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 we 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 level, the Machine level, and the User level.

The Virtual Execution System within the CLR loads and runs programs. It provides the functionality needed to execute managed code and uses assembly metadata to connect modules together at run time. When the VES loads an assembly, the VES matches the assembly to one or more of a number of code groups. Each code group is assigned one or more permissions that specify what actions assemblies in that code group can do. 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 a Membership Condition . For an assembly to be filed into a code group, it must match the group's membership condition. Membership conditions are things like "the assembly is from the site http://www.microsoft.com " or "the Publisher of this software is Microsoft Corporation".

Each code group has one, and only one, membership condition. Here are 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, often called a 'shared name'.

  • 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 - code requests 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 type of membership condition in the list is the Zone condition, which is one of the most commonly used. A zone is the region of origin of a piece of code and is one of the following: MyComputer , Internet , Intranet , Trusted , or Untrusted . These zones are managed using the Security Options in Internet Explorer, and we'll see more about these later in the chapter when we look at how to manage security policy. 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 in a hierarchy, with the All Code membership condition at the root:

click to expand

You can see that each code group has a single membership condition and specifies the permissions that the code group has been granted. We'll see more about permissions later. 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.

Caspol .exe - Code Access Security Policy Tool

The command-line Code Access Security Policy tool is the one we'll spend the most time looking at in this chapter. It lets us view and manage security policy. To get a list of options for the tool, just type the following at the command prompt:

 >  caspol.exe -?  

Alternatively, to send the output to a text file use:

 >  caspol.exe  >  caspol.txt  

.NET also includes a snap-in for the Microsoft Management Console to manage code access security; however, we will restrict ourselves to the command-line utility as the examples are easier to follow, and you'll also be in a position to create scripts to alter security policy, which is very useful when applying policies to large numbers of machines.

Let's have a 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 it gives 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 1.0.3705.0 Copyright (C) Microsoft Corporation 1998-2001. 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 gro up tree.    1.1. My_Computer_Zone: Code group grants full trust to all code originating o n 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 cod e 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 limi ted access to environment variables.       1.2.1. Intranet_Same_Site_Access: All intranet code gets the right to conn ect 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 Interne t permission set. This permission set grants Internet code the right to use isol ated storage and limited UI access.       1.3.1. Internet_Same_Site_Access: All Internet code gets the right to conn ect 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 permissio n 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 connec t back to the site of its origin. 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. For example, 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, we can specify what level of trust we 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, open up a command prompt, and type this command:

 >  caspol.exe -listgroups  

You will see something like this:

 Microsoft (R) .NET Framework CasPol 1.0.3705.0 Copyright (C) Microsoft Corporation 1998-2001. 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, we see that it can be turned off and then back on.

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

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

As code is broken down into these groups, we 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 (such as 1.2 ). These labels are auto-generated by .NET, and can differ between machines. We do not generally manage security for each assembly; we do it using a code group.

You may be curious how caspol.exe operates when a machine has several side-by-side installations of .NET. Under these circumstances, the copy of caspol.exe that you run will only alter the security policy for its associated installation of .NET. To keep security policy management simpler, you may well want to remove previous copies of .NET as you install successive versions.

Viewing an Assembly's Code Groups

Assemblies are matched to code groups dependent upon the membership conditions they match. If we go back to our example code groups and load an assembly from the https ://intranet/ web site, it would match code groups like this:

click to expand

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

 >  caspol.exe -resolvegroup assembly.dll  

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

 Microsoft (R) .NET Framework CasPol 1.0.3705.0 Copyright (C) Microsoft Corporation 1998-2001. 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, just stay focused on the Machine level. We'll look at the other two in much more detail later in the chapter. 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 let's use this command against the same assembly, but across HTTP to a remote server, we'll 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 1.0.3705.0 Copyright (C) Microsoft Corporation 1998-2001. 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 permissions and the Same Site Web permissions. The intersection of the permissions will allow the code limited UI access, and will allow it to make connections back to the site it originated from

Let's take a closer look at permissions - the freedom we allow assemblies matched to each code group.

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 clearly immensely useful for the CLR to collect evidence on code before it executes it, but equally, you as the administrator must have the opportunity to strictly control what code is allowed to do on the several hundred machines you manage once the CLR knows where it came from. This is where permissions come into the equation.

Once 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 2000 we generally don't apply permissions to users, we apply permissions to groups. The same is true with assemblies; we apply permissions to code groups rather than individual assemblies, which makes the management of security policy in .NET a much easier task.

The security policy specifies what actions assemblies in a code group are permitted to perform. Let's look at the code access permissions provided by the CLR. As you can see from the following list, there are many of them, giving us a high degree of control over what code is allowed to do or not allowed to do:

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

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

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

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

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

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

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

  • IsolatedStoragePermission - the ability to access isolated storage; storage that is associated with an individual user and with some aspect of the code's identity, such as its web site, signature, or publisher.

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

  • OleDbPermission - the ability to access databases with OLE DB.

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

  • PrintingPermission - the ability to print.

  • ReflectionPermission - the ability to discover information about a type at run time using System.Reflection .

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

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

  • ServiceControllerPermission - the ability to access (running or stopped ) Windows Services.

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

  • SQLClientPermission - the ability to access SQL databases.

  • UIPermission - the ability to access the user interface.

  • WebPermission - the ability to make or accept connections to/from the web.

With each of these permission classes, we can often specify an even deeper level of granularity. For example, later in the chapter you'll 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 the resources relating to the permissions in this list are enclosed within trycatch 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; you should not assume that it will be running under the same security policy under which you develop it. For example, if your application cannot access the local drive, should it exit, or operate in an alternative fashion?

An assembly will be 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 will extend what it is allowed to do. Do note that code groups down the tree will often be assigned more relaxed permissions than those above.

There is another set of permissions that are assigned by the CLR on the basis of the identity of the code, which cannot be explicitly granted. These permissions relate directly 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 - the software publisher's digital signature

  • SiteIdentityPermission - the location of the web site from which the code originated

  • StrongNameIdentityPermission - the assembly's strong name

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

  • ZoneIdentityPermission - the zone from which the assembly originates

Usually, we'll apply permissions in blocks, which is why .NET also gives us Permission Sets . These are lists of code access permissions grouped into a named set. Here are the named permission sets we get straight out of the box:

  • FullTrust - no permission restrictions.

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

  • Nothing - no permissions and unable to execute.

  • LocalIntranet - 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 - 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 - all the permissions 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.

    Do note that of these you can only change the definitions of the Everything permission set - the first five 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 give it the identity permissions associated with another publisher. The CLR grants identity permissions where necessary, and we can then make use of them if we wish.

Viewing an Assembly's Permissions

Imagine you're using an application written by Microsoft, and you attempt to use a feature that you have not used before. The application does not have a copy of the code stored locally, so it requests it and the code is then downloaded into the Global Assembly Cache. Under a scenario like this, with code from the Internet published by a named organization that has signed the assembly with a certificate, we'll find the assembly's code group membership looks something like this:

click to expand

According to our policy in this example, although the All Code and Internet code groups bring only limited permissions, 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 in this way, the effective permission is that of the highest permissions granted. That is, each code group an assembly belongs to brings additional permissions.

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

 >  caspol.exe -resolveperm assembly.dll  

Let's try this on an assembly, and look at the code access and identity permissions it is granted when we access it over a local intranet. If we type the following command we see the code access permissions and then the three identity permissions at the end:

 >  caspol.exe -resolveperm http://intranet/assembly.dll  Microsoft (R) .NET Framework CasPol 1.0.3705.0 Copyright (C) Microsoft Corporation 1998-2001. All rights reserved. Resolving permissions for level = Enterprise Resolving permissions for level = Machine Resolving permissions for level = User Grant = <PermissionSet class="System.Security.PermissionSet"                version="1">    <IPermission class="System.Security.Permissions.FileDialogPermission,                         mscorlib, Version=1.0.3300.0, Culture=neutral,                         PublicKeyToken=b77a5c561934e089"                 version="1"                 Access="Open"/>    <IPermission class="System.Security.Permissions.IsolatedStorageFilePermission,                        mscorlib, Version=1.0.3300.0, Culture=neutral,                        PublicKeyToken=b77a5c561934e089"                 version="1"                 Allowed="DomainIsolationByUser"                 UserQuota="10240"/>    <IPermission class="System.Security.Permissions.SecurityPermission,                        mscorlib, Version=1.0.3300.0, Culture=neutral,                       PublicKeyToken=b77a5c561934e089"                 version="1"                 Flags="Execution"/>    <IPermission class="System.Security.Permissions.UIPermission,                        mscorlib, Version=1.0.3300.0, Culture=neutral,                       PublicKeyToken=b77a5c561934e089"                 version="1"                 Window="SafeTopLevelWindows"                 Clipboard="OwnClipboard"/>    <IPermission class="System.Net.WebPermission,                         System, Version=1.0.3300.0, Culture=neutral,                        PublicKeyToken=b77a5c561934e089"                 version="1">       <ConnectAccess>          <URI uri="(httpshttp)://some\.host\.com/.*"/>       </ConnectAccess>    </IPermission>    <IPermission class="System.Drawing.Printing.PrintingPermission,                        System.Drawing, Version=1.0.3300.0, Culture=neutral,                       PublicKeyToken=b03f5f7f11d50a3a"                 version="1"                 Level="SafePrinting"/>    <IPermission class="System.Security.Permissions.SiteIdentityPermission,                        mscorlib, Version=1.0.3300.0, Culture=neutral,                       PublicKeyToken=b77a5c561934e089"                 version="1"                 Site="some.host.com"/>    <IPermission class="System.Security.Permissions.UrlIdentityPermission,                         mscorlib, Version=1.0.3300.0, Culture=neutral,                        PublicKeyToken=b77a5c561934e089"                 version="1"                 Url="http://some.host.com/dev/testdll.dll"/>    <IPermission class="System.Security.Permissions.ZoneIdentityPermission,                        mscorlib, Version=1.0.3300.0, Culture=neutral,                       PublicKeyToken=b77a5c561934e089"                 version="1"                 Zone="Internet"/> </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 it is possible for us to create our own permissions, and you'll see more about that later. We 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. Let's look at these now.

Policy Levels: Machine, User, and Enterprise

Up to now we have looked at 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 levels of code groups:

  • Machine

  • Enterprise

  • User

The code group levels are independently managed and exist in parallel:

click to expand

If there are three security policies, how do we know which applies? The effective permission is the intersection of the permissions from the three levels. Each of the three levels has the ability to veto the permissions allowed by another - this is clearly good news for administrators as 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 we've been using it up to now. Let's 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 let's run the same command, but this time to see 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 level, and the enforced policy is dictated solely by the machine-level policy. For example, if we 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, so, for example, if we want to apply FullTrust to a code group, that permission must be assigned to the code group on each of the three policy levels.

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

Now we've had a high-level look at the security architecture in .NET, let's look at how we can access its features programmatically.

  


Professional C#. 2nd Edition
Performance Consulting: A Practical Guide for HR and Learning Professionals
ISBN: 1576754359
EAN: 2147483647
Year: 2002
Pages: 244

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