Chapter 17. Security and Cryptography

This chapter details the support for security and cryptography in the Microsoft .NET platform. The support for cryptographic operations and role-based security should be easily understood by experienced Java developers, but the .NET Code Access Security (CAS) model has no direct parallel in Java. Although some of the concepts may seem awkward, the system does offer significant benefits, especially for those programmers who write code to be used by third parties.

Code Access Security

The .NET Framework CAS model is similar to an expanded implementation of the Java security manager. CAS controls access to protected resources (such as the file system) and can be used to prevent applications from performing certain operations (such as opening a network connection or reading a file). We say that CAS is similar to an expanded Java security manager because the .NET Framework provides very fine grain controls for protected resources and the security model is tightly integrated into the runtime model.

When a .NET application is started, the common language runtime (CLR) checks to see which permissions should be granted to the code; the CLR will throw a System.Security.SecurityException if an application attempts to perform an operation requiring a permission that has not been granted.

The rules determining the set of permissions that should be granted are applied at the assembly level. Each assembly is evaluated individually to determine the policies that should be applied using a technique known as evidencebased security, by which characteristics of an assembly (such as the publisher or source URL) are assessed to determine which permission policies are relevant. The permissions defined by the policies that apply are then granted to the assembly.

Programming for CAS

Programmers aren’t required to make explicit use of CAS in code, although there are benefits in doing so, especially for assemblies that are shipped to third parties. The benefits of CAS include the following:

  • CAS allows administrators to easily assess the security requirements of an assembly, allowing an informed decision to be made when determining the level of trust to grant an application or library.

  • CAS allows programmers to tailor the behavior of an assembly to work within a security policy by requesting optional permissions; for example, a CD player can provide song lists to the user, but only if the security policy allows Internet connections to be made so that the player can look up the CD details.

  • CAS allows programmers to protect their code against subversion; assemblies that never need access to a protected resource can be written to ensure that the code isn’t tricked into performing a task that wasn’t intended by a programmer.

Ignoring the CAS support doesn’t exempt an assembly from security policies; administrators can still apply restrictions to an assembly. Code that has been written without taking CAS into consideration can behave unexpectedly: security exceptions may be thrown, and the applications will have no means of recovering.

CAS permissions are defined by a set of attribute classes that implement the abstract System.Security.CodeAccessPermissionClass. Table 17-1 details the most commonly used attributes.

Table 17-1. CAS Permission Classes

Attribute Class Name

Permission Represented

System.Net.DnsPermission

Accessing the DNS

System.Security.Permissions.EnvironmentPermission

Reading and writing environment variables

System.Diagnostics.EventLogPermission

Reading and writing to event log services

System.Security.Permissions.FileDialogPermission

Accessing files that are selected by the user via a file dialog window

System.Security.Permissions.FileIOPermission

Reading, appending, or writing files or directories

System.Security.Permissions.IsolatedStorageFilePermission

Accessing private virtual file systems

System.Drawing.Printing.PrintingPermission

Accessing printing services

System.Security.Permissions.RegistryPermission

Reading or modifying the Windows registry

System.Net.SocketPermission

Opening socket connections to remote machines

System.Data.SqlClient.SqlClientPermission

Accessing SQL servers

System.Security.Permissions.UIPermission

Creating user interfaces

System.Net.WebPermission

Accessing HTTP Internet resources

Declarative CAS Statements

Declarative statements—also known as soft statements—are a means of indicating the permissions that an assembly requires. The CLR reads the declarative statements from an assembly prior to execution; if the required permissions cannot be granted, a System.Security.SecurityException will be thrown and the code will not be executed.

Declarative CAS statements fall into three categories—minimum permissions, optional permissions, and denied permissions—as described here:

  • Minimum permissions are those that an application needs in order to provide core services and cannot function without.

  • Optional permissions are those that the application would like to have (perhaps in order to offer additional features) but that are not essential.

  • Denied permissions are those that the application should never be granted, even if they’re permitted by the CAS security policies.

Statement Scope

Declarative statements can be applied to an assembly, a class, or a method; this approach allows the programmer to limit the scope of permissions. Declarative CAS statements cannot be applied to other member types, such as properties or indexers. The following example demonstrates the three statement scopes, which appear in boldface:

using System;
using System.Security.Permissions;

[assembly:FileIOPermissionAttribute(SecurityAction.RequestMinimum,
    Unrestricted = true)]

[EnvironmentPermission(SecurityAction.Demand, Unrestricted=true)]
  class MyClass {

    [System.Net.WebPermission(SecurityAction.Demand, Unrestricted=true)]
    public void myMethod() {
        // method statements
    }

    public void myOtherMethod() {
        // methods statements
    }

    public static void Main() {
    }
}

class MyOtherClass {
    // class definition statements
}

The syntax of these statements is explained here:

  • The first statement, prefixed with assembly, requests access to the file system for the entire assembly; any method contained in MyClass and MyOtherClass can make calls that access the file system.

  • The second statement requests permission for all methods of MyClass to be able to read and write environment variables. This permission will not be available to methods of MyOtherClass.

  • The third statement requests access to HTTP Internet servers for the MyClass.myMethod method; this permission will not be available to MyClass.myOtherMethod or to any method of MyOtherClass.

Declarative Statement Syntax

The first argument for a declarative attribute is a value from the System.Security.Permissions.SecurityAction enumeration; this value allows the programmer to specify the kind of CAS request that the statement represents. Not all values can be applied for all permission scopes. Table 17-2 details these values.

Table 17-2. SecurityAction Values

Value

Scope

Action

RequestMinimum

Assembly

A request for the minimum permissions required for the code to run.

RequestOptional

Assembly

A request for additional permissions that are optional (not required to run).

RequestRefuse

Assembly

A request that permissions that might be misused should not be granted to the calling code.

Demand

Class, method

All callers higher in the call stack are required to have been granted the permission specified by the current permission object.

Assert

Class, method

The calling code can access the resource identified by the current permission object, even if callers higher in the stack haven’t been granted permission to access the resource.

Deny

Class, method

The ability to access the resource specified by the current permission object is denied to callers, even if they have been granted permission to access it.

The second argument represents a property that will be used to control the way that the permission restricts access to the protected resource. The statements in the preceding example all used the Unrestricted=true argument, which specifies that the declarative statement applies to all aspects of the protected resource—for example, allowing access to all HTTP servers.

The Unrestricted property is the only one that is common to all permission classes; each class defines a unique set of properties that reflect how the permission is applied. For example, the WebPermission class shown in the preceding example defines the Connect property that specifies the URL to which the permission applies. The following statement demonstrates how to combine the SecurityAction.Deny value with the WebPermission.Connect property to prevent access to a specific URL:

[System.Net.WebPermission(SecurityAction.Deny,
    Connect="http://www.mycompany.com/index.html")]

More Info

Consult the .NET documentation on each permission attribute for details of the properties that are available.

Using Optional Permissions

Requesting optional permissions allows an application to gracefully reduce functionality when CAS permissions are not granted. Consider an HTML browser; the core function of the browser is to read and display HTML files from Web servers. The browser may offer additional features such as caching the HTML file to disk to improve performance for future requests.

Some customers might trust the company that produces the browser and configure the CAS policy to allow access to the file system; other customers might not want the browser to access the file system at all. By requesting optional permissions, the browser can operate in both environments. Customers who allow cached files might benefit from improved performance; customers who don’t allow cached files can still view HTML pages.

The following code fragment demonstrates how optional permissions can be used. Note that the CLR throws a SecurityException when an operation that requires an optional permission is attempted and the permission hasn’t been granted; it’s the responsibility of the programmer to catch this exception.

using System.Security;
using System.Security.Permissions;

[assembly:FileIOPermissionAttribute(SecurityAction.RequestOptional,
    Unrestricted = true)]

class OptionalPermissionDemo {

    public void loadHTMLFile(string p_url) {
        if (isPageCached(p_url)) {
            // statements to process the cached data
        } else {
            // statements to connect to the server
            // and obtain the web page
        }
    }

    private bool isPageCached(string p_url) {
        try {
            // code to determine if there is a
            // cached version of the HTML page
        } catch (SecurityException) {
            // the optional file system permission
            // has not been granted
            return false;
        }
    }
}

Refusing Permissions

The benefit of refusing permissions is to reduce the likelihood of code being subverted into performing tasks that the programmer didn’t intend. Consider the following example, which prints the contents of a URL to the console:

using System;
using System.Net;
using System.Text;
using System.Security.Permissions;

class MyClass {

    [FileIOPermission(SecurityAction.Deny, Unrestricted=true)]
    public void printURL(string p_target) {
        WebClient x_client = new WebClient();
        byte[] x_data_array = x_client.DownloadData(p_target);
        String x_data_string = Encoding.Default.GetString(x_data_array);
        Console.WriteLine(x_data_string);
    }

    static void Main(string[] p_args) {
        new MyClass().printURL(p_args[0]);
    }
}

The CAS statement requests that the printURL method never be allowed access to the file system; without this statement, the method could be used to read files from the disk using URLs of the form file://c:myfilename. With this statement, the programmer can be sure that the code won’t be subverted into reading the contents of files when the intended purpose of the code is to read the contents of remote URLs.

Although the example shown in this section is contrived, the impact of refusing permissions is significant and can be a considerable help in ensuring that code shipped to customers and other third parties is less likely to be subverted to compromise security.

Assessing Declarative Statements

The Permission Viewer tool (permview.exe) is used to view the permissions that an assembly has requested via declarative statements. By default, the output of permview displays only the permission statements requested for the entire assembly; the /DECL switch includes class and method scope permission requests.

The example listed previously in the Statement Scope section of this chapter produces the following output from permview:

Microsoft (R) .NET Framework Permission Request Viewer.  Version 1.0.3705.0
Copyright (C) Microsoft Corporation 1998-2001. All rights reserved.

Assembly RequestMinimum permission set:
<PermissionSet class="System.Security.PermissionSet" version="1">
   <IPermission class="System.Security.Permissions.FileIOPermission,
       mscorlib, Version=1.0.3300.0, Culture=neutral,
       PublicKeyToken=b77a5c561934e089"
       version="1"
       Unrestricted="true"/>
</PermissionSet>

Class MyClass Demand permission set:
<PermissionSet class="System.Security.PermissionSet" version="1">
   <IPermission class="System.Security.Permissions.EnvironmentPermission,
        mscorlib, Version=1.0.3300.0, Culture=neutral,
        PublicKeyToken=b77a5c561934e089"
        version="1"
        Unrestricted="true"/>
</PermissionSet>

Method MyClass::myMethod() Demand permission set:
<PermissionSet class="System.Security.PermissionSet" version="1">
   <IPermission class="System.Net.WebPermission, System,
        Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
        version="1"
        Unrestricted="true"/>
</PermissionSet>

The output shows the permission set requested at each level, including the details of the assembly that contains the permission class that has been used.

Imperative Security Demands

Imperative statements—also known as hard statements—request CAS permissions at run time, in contrast with declarative statements, which can be assessed before the code in an assembly is executed. Imperative statements are useful when the details of the resource to be accessed aren’t available ahead of execution—for example, writing to a file that the user has specified via a dialog box. The disadvantage of imperative statements is that the specific security demands of an assembly can be determined only at run time, so a system administrator cannot assess the security demands of an assembly in order to determine a suitable level of trust.

Imperative statements are made by creating a new instance of a permission class and then calling the Assert, Deny, or Demand method; these methods relate to the values of the SecurityAction enumeration described in the preceding section. Each permission class provides different constructor forms; consult the .NET documentation for more information. The following example demonstrates how to make a simple imperative statement using the FileIOPermission class:

public void readFile(string p_file_name) {

    FileIOPermission x_perm = new FileIOPermission(
        FileIOPermissionAccess.Read,
        new string[] {p_file_name});

    x_perm.Demand();

    // statements to operate on the file
    // specifed in the method argument
}

The example demands permission to read the file that is passed in by name as a method argument; this would not be possible to implement using declarative statements. The Demand method returns void; if the permission is not granted, an instance of System.Security.SecurityException will be thrown.

CAS Policies

The .NET Framework determines the CAS permissions to grant to an assembly by inspecting a hierarchy of security information, known as the CAS security policy. The permissions described in the preceding section are grouped into permission sets. One or more permission sets can be associated in a code group, which also includes a name and a membership condition. A permission set can be included in multiple code groups. The membership condition specifies a characteristic to look for in an assembly; if the assembly displays the characteristic, the permissions contained in the code group should be applied and the assembly is said to be a member of the code group. Table 17-3 describes the most commonly used membership characteristics.

Table 17-3. Code Group Membership Conditions

Membership Condition

Description

All Code

Applies to every .NET assembly; used to specify default policies.

Application Directory

Applies to assemblies installed alongside the current application.

Cryptographic Hash

Applies to assemblies that have a specific hash value. See the Hash Codes section later in this chapter for more information.

Site Membership

Applies to assemblies that were obtained from a specific FTP or HTTP server.

Strong Name

Applies to assemblies that have a specific strong name. See Appendix B, for more information.

At the top of the hierarchy are policy levels, which contain a set of code groups. The policy levels are as follows:

  • Enterprise. Applies to all machines in an enterprise, where the policy details may be automatically distributed.

  • Machine. Applies to a single machine.

  • User. Applies to the current user.

A security policy is determined by examining the code groups contained in each policy level and establishing whether an assembly is a member of each one; the sum of the permissions included in all code groups of which the assembly is a member will be granted. Note that the policy levels are searched in the sequence just listed and that lower policy levels can restrict only the permissions granted at higher levels; for example, the User policy level cannot grant more permissions to an assembly than the Machine level.

The programmer isn’t responsible for determining security policies, only for using CAS statements to declare the permissions that an assembly requires. The system administrator uses the CAS information (via the permview tool) to assess security requirements and determine an appropriate level of trust.

The simplest way to manage CAS policies is through the .NET Framework Configuration tool, which can be found in the Administrative Tools section of the Windows Control Panel. This tool allows the administrator to graphically configure policies and assess assemblies to see which permissions or code groups will be applied. The .NET Framework also includes the caspol.exe tool to manage CAS policies from the command line; this tool uses XML files to express permission settings. Consult the .NET documentation for more details on using these tools.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset