Description:  This document is a tutorial in a series of tutorials for programmers learning about the .NET Framework development environment.  What you will learn is how the security features of the .NET Framework behave, and how you can take advantage of them in your software.

Requirements:  You should be familiar with at least one programming language, such as C++, Pascal, PERL, Java or Visual Basic.  This tutorial assumes familiarity with the Common Language Runtime and the .NET Framework in general.  Introductory tutorials on both of these topics have already been released in this tutorial series.  To do the exercises and run the examples you need a PC running Windows with the .NET Framework SDK installed.

Table of Contents

Table of Contents. 1

Figures and Exercises. 2

1.     Security and the .NET Framework. 3

1.1.      The .NET Framework. 3

1.2.      Security Features of the Host OS.. 4

1.3.      Security Goals of the .NET Framework. 4

2.     Introductory Code Access Security. 6

2.1.      Defining Code. 8

2.2.      Demand. 8

2.3.      Permissions. 10

2.4.      Zones. 11

3.     Practical Security Programming. 14

3.1.      SecurityException 101. 14

3.2.      Zone Testing. 15

4.     Advanced Code Access Security. 16

4.1.      Policy and administration. 16

4.2.      Evidence. 16

4.3.      Code Groups. 17

4.4.      Permission Sets. 17

4.5.      Loading an Assembly. 17

4.6.      Defining Secured Components. 17

4.7.      The Security Stack. 18

5.     Code Access Security. 19


Figures and Exercises

Figure 2‑1  DisplayFile.cs. 6

Figure 2‑2  Demand. 9

Figure 2‑3  Partial List of Standard Permissions. 11

Figure 2‑4  Zones. 12

Figure 2‑5  Zoner.cs. 13

Figure 3‑1  GracefulDisplayFile.cs. 15

Figure 4‑1  Stack Modifications. 19

Exercise 2‑1  Testing DisplayFile.cs. 7

Exercise 2‑2  Testing CAS with DisplayFile.cs Part 1. 7

Exercise 2‑3  Testing CAS with DisplayFile.cs Part 2. 7

Exercise 2‑4  Testing DisplayFile.cs using Zoner.cs. 14

Exercise 3‑1  Zone testing Pad.cs. 15

 


 

 

1.   Security and the .NET Framework

Computer security is technology designed to protect resources.  The resources being protected vary widely, as does the technology and nature of the protection.  In fact, computer security is such a diverse field that it is often inappropriate to use a term as general as security to discuss the topic.

To provide some perspective, let’s take a short look at the types of resources that are traditionally protected via computer security.

·          The file system

·          System memory

·          Communication data

·          Identification data

·          Bandwidth (CPU, network, etc.)

·          Screen and GUI data

This list is by no stretch of the mind complete, but it does show some otherwise unrelated resources in a system that require protection.  Security technologies themselves also come in a variety of forms.

·          Authentication and user management

·          Authorization and access control

·          Encryption and key management

·          Address space and process boundaries

·          User Logon-session boundaries

·          Key exchange and communication protocols

Many books have been written on each of the preceding topics individually, and still each of these topics can be subdivided further.

1.1.        The .NET Framework

When designing the .NET Framework, Microsoft had to decide how the platform was going to address security.  Was the .NET Framework going to be a comprehensive secure solution, including user databases, logons, authentication, and the works?  Or was the .NET Framework going to rely on underlying technologies, such as services provided by the host operating system?  The answer is that the .NET Framework does both.

The .NET Framework itself actually implements only a single comprehensive form of security known as Code Access Security.  Code access security (or CAS) is a security subsystem built into the .NET Framework that is both reliant on other features of the framework (such as JIT compilation and garbage collection), as well as relied upon by the rest of the platform.  CAS is a part of the .NET Framework that affects almost every other part of the .NET Framework, and is largely the focus of this tutorial.

However, before jumping into the details of Code Access Security, it can be helpful to touch upon the parts of security that the .NET Framework borrows from its host OS.  Let’s take, for example, encryption.

1.2.        Security Features of the Host OS

General encryption is not a feature implemented by the .NET Framework per-se.  However your managed code has access to rich encryption ability.  This is because the .NET Framework currently runs on Windows, and Windows’ Crypto-API is a very powerful encryption engine.  Rather than rewrite these encryption providers, the .NET Framework Class Library (or FCL) provides an extensive set of types (found in the System.Security.Cryptography namespace) that wrap the API of the host OS. 

If the .NET Framework were to run on a less capable OS, however, it would be entirely possible to move the encryption implementation into the FCL itself.  This, in fact, is likely to happen as the .NET Framework platform moves to lighter weight devices such as PDA’s.  In this way, the .NET Framework does not provide a security service, but rather a wrapper of one that may at one time become a full-fledged implementation.

In contrast, there are some security features that the .NET Framework is not going to attempt to provide, unless it is provided by the host OS.  In these cases, the overall security story will differ depending on the host OS.  An example of this is user authentication and account management.  The .NET Framework does not provide these features, nor are there any plans for a future implementation.  This simply is not part of the goals of the .NET Framework.

What this means is that if the .NET Framework is installed on a system that implements user authentication and account management, then the code that runs on the .NET Framework will be subject to the user-based security of the host.  However, if the .NET Framework is installed on an OS with no user-based security, then managed code in that environment simply won’t have or be subject to the missing feature.

In more concrete terms, when managed code is running on Windows 2000 or Windows XP, it benefits from the rich access control of the file system, protected process address space, user authentication, etc.  However, when managed code runs on Windows 98 or Windows ME, these security features do not exist, or exist in a much more limited fashion. 

1.3.        Security Goals of the .NET Framework

Knowing the goals of the .NET Framework will help you to grasp the resulting technologies.  Here are some goals.

·          Perform authentication of code (rather than user authentication).

·          Potentially limit access to system resources through authorization based on code-based authentication.

·          Reduce the granularity of security to units of executing code smaller than a single process or application.

·          Provide a security mechanism to ensure a users ability to safely execute code that originated from a wide variety of sources (including the Internet).

These goals are pretty specific, but there are actually a couple of important code scenarios that they promote.  These are the Mobile Code scenario and the ISP scenario.

In the mobile code scenario, code exists on some remote location such as an Internet server, or a share in an enterprise.  The user initiates the downloading and local execution of this code.  This can be in the form of a control in a browser, or as a free-standing executable downloaded from the network and run locally.  Either way, mobile code is code that meets two criteria: it executes locally and it was potentially developed by someone that you do not know or trust.

The idea behind mobile code is that great majority of developers that you do not know or trust have no ill-intent towards you or your system, and develop usable or entertaining software.  Meanwhile, if that software runs locally on your system, you as the user gain the advantage of performance and rich features over a server-side implementation.

The mobile code scenario is important.  It is a goal of the .NET Framework to alleviate the potential problems with mobile code such as worms, Trojans and viruses.

Let’s move on to the ISP scenario.  ISP stands for Internet Service Provider.  Most ISPs provide some means of web-hosting for their clients.  This can range from a few megabytes of disk space for static content to full fledged hosted machines or networks of machines. 

The problem with the ISP scenario really lies with the smaller hosts.  These are the small business or personal websites that are likely to share a single machine or group of machines with other clients of the ISP.  In these cases, there are some real security problems associated with executing code to produce dynamic web-pages.  This includes servlets, ISAPI DLL’s, CGI scripts and executables, ASP and a host of other technologies.

The problem is that running code on the server side is a security risk.  One client may purposefully or inadvertently cause harm to another client’s data or page.  In fact, it is feasible that a single client could bring down the entire server machine.

Currently the solution to this problem is to keep server-side technologies limited to scripts or interpreted code.  This causes performance to be bad, and often the technologies must also have severely limited access to the API of the system.  Many ISP’s simply deny their clients the ability to host anything other than a static web-site unless they pay the price for a dedicated machine.

It is a goal of the .NET Framework to allow an ISP to run server-side code in the native machine language of the system.  Meanwhile the code runs in the same process with other server-side code, but the .NET Framework provides sufficient isolation to keep all clients and the system itself safe. 

We have talked about the technical goals of the .NET Framework, and we have discussed a couple of scenarios that the .NET Framework seeks to enable.  This should give you sufficient background to begin looking at Code Access Security.

2.   Introductory Code Access Security

The basic operation of CAS is actually pretty simple. 

·          When the Common Language Runtime (CLR) loads code, the code is authenticated.  What this means is that the CLR uses knowledge, known as evidence, that it has about the code (such as its origin) to establish a group that the code belongs to.

·          Once a code group is established, permissions are assigned to the code, and then the code is allowed to execute.

·          While executing, the codes permissions are checked at appropriate times to restrict the actions that the code can take.  If the code attempts a restricted action, a SecurityException is thrown.

Let’s look at a concrete example.

using System;

using System.IO;

using System.Security;

 

class App{

   public static void Main(string[] args){

      StreamReader reader = new StreamReader(args[0]);

      Console.WriteLine(reader.ReadToEnd());     

   }

}

Figure 21  DisplayFile.cs

The code in Figure 21 is a very simple application that will display any text file to the console window.  In fact, does not directly address security in any way.  However, the code does access a potentially protected resource, and that is the file that it reads before it writes the contents to the console window.

This file access is actually performed by the implementation of the StreamReader class in the example.  Depending on the results of authentication by the CLR, this code will either execute or throw a SecurityException when it attempts to access the general file system.

Note: The code shown in Figure 2‑1 could execute inside of a try-catch(SecurityException) block.  This would allow the code to gracefully recover from its inability to read the file.  In fact, this kind of exception handling is a key factor in addressing security with your managed code.

If you are interested in seeing CAS in action, compile the code in Figure 2‑1 into an executable.  Run the executable from your local file system and display a text file on your local file system.  All should work fine.  Now copy your executable to a network share.  Execute the file from the share, but display the same file from your local file system.  You should see the CLR halt execution of DisplayFile.exe by throwing a SecurityException.

Exercise 21  Testing DisplayFile.cs

  1. Build the code in Figure 2‑1 into a DisplayFile.exe console application.
  2. Copy DisplayFile.exe to its own directory on your local file system.
    Example:  C:\DSTest\
  3. Create a text file (with some text in it) in the same directory. 
    Example: 
    C:\>Notepad C:\DSTest\Test.txt