#Google Analytic Tracker

Pages

Feb 3, 2008

Some .NET Application Security Experience

While there are so many hype on .NET Framework 3.0 and 3.5, I am still studying .NET 2.0 for a MCTS exam.

In my past experience, I rarely deal with .NET programming using its build-in security framework.

Introduction

CAS (Code Access Security), is a .net security system that allow administrators to control .net application authorization to the OS resource. This security system ONLY works for .NET application (or managed code). It can't have security control on (unmanaged code).

For example, say your .NET application called a Excel COM library function, or calling a dll imported function, even you set your .net application no write access to C drive, it only means within your .NET application has no access to write on C drive. Your unmanaged dll will still able to write access to C drive as long as your OS allowed it to.

Layers of Security

Here is the basic security layers on how a user get access to the computer's resources:

  User's Action (i.e. click a button)
Your Application .NET Application Assembly
  .NET Framework CAS
  Operation System Security (i.e. Windows RBS)
Resources: Hard Disk, Registry, Printers, etc...

RBS - Role Base Security (Security based on user credential such as Administrator, Power User, System User, Guest, etc)

The first line of your application security defence is your .net assembly itself. You can prevent user from access resources programmatically. However, when you are running an unknown assembly that you are not comfortable with (say you downloaded a program, but don't want this program to access your C:\Windows\ directory, this is where CAS comes into play. Depending on the type or how your assembly is beginning execute (i.e. execute from web vs. from local computer) and etc, different permissions can be apply to your assembly.

However, even you give a write C:\ drive permission on .NET CAS level, if your OS doesn't allows your application to write to C:, say you log on as a Guest, .NET Framework will throw you a System.UnauthorizedAccessException.

How to configure the CAS

Other than using .NET Framework Caspol tool, which is usually located at C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Caspol.exe, you should use the NET 2.0 Framework Configuration Tool.

Go to Control Panel -> Administrative Tools -> Microsoft .NET Framework 2.0 Configuration.

image

Under the Runtime Security Policy tree node, you will find all the CAS related settings.

In general, all assembly execute with something call Evidence. Evidence is basically your assembly's identification. Evidence can be the assembly's hash code, its Strong Name, its URL that it downloaded from (i.e. www.microsoft.com/assembly.exe), its site (i.e. www.microsoft.com), publisher or its Zone. Please refer to Evidence Class for details

image

Basics

First, when your assembly runs, it has to check though all 3 levels (Enterprise, Machine, and User). Your assembly will be checked though all 3 levels. CAS will takes the minimal set of all 3 level permissions. So say if under machine level, your assembly can't write to C:\Windows, even on Enterprise or User allows your assembly to do so, CAS will not let your application to write to C:\Windows.

Second, when CAS elevates your assembly for each level, it determines which "code" your assembly belong to. Is your assembly running under "My_Computer_Zone", or under "Internet_Zone" (see above diagram). An assembly can beyond to multiple code. For example, it can be in a "My_Computer_Zone", while it is also in "MyCodeGroup" (a custom one that I personally made) . CAS will take the union of all the code group and combine together them together.

If you don't want your application to have multiple permission, you can set the "This policy level will only have ...." option in the code group setting.

image

This way, even your assembly has access write to c:\ drive because it belongs to "My_Computer_Zone", since you set this option, the My_Computer_Zone no longer apply (like a intersection, instead of union) .

Membership Condition

In each code group, you can set the "Membership Condition". You can say if your assembly run from a specific URL, it will belong to this group, or if your assembly has a particular strong name, it will belong to another group. You can even made your custom condition, which I personally have no idea how to make one.

Example (any assembly has this Strong Name belong to "Local_Shared_Folder" code group that I made):

image

Permission Set

Notice that by default, .NET 2.0 configuration comes with these permission sets.

Permission Sets Name Brief Description
FullTrust Unrestricted access to all protected resources
SkipVerification Grants assembly right to bypass the verification
Execution Permit assembly to execute (doesn't mean it can access protected resources!)
Nothing Denies all resources, not even execution (Of course, if the assembly has skipverification permission, it can easily by pass this nothing...I guess)
LocalIntranet Some default permissions ideal for local intranet application
Internet Some default permissions ideal for Internet application
Everything Allows unrestricted access to all resources covered by .NET build-in permissions.

For example: My_Computer_Zone's permission set is "FullTrust", while Restricted_Zone's permission set is Nothing. If your assembly happens to have both of these zone (which it shouldn't), since CAS takes the union of all permission, your assembly will still able to access the FullTrust permission sets. That's why the option of setting policy level with the only grant permission helps.

The Everything Permission Set

Here is a list of all the build-in permissions.

image

Declarative and Imperative Security

Here is the confusing part about CAS and this "declarative and imperative security" when I first study the .NET security.

Since now you know how administrator can limit your assembly to access certain resources, as a developer, you should write your program to participate in the event when your assembly runs into security problems.  Otherwise, your assembly will get a very unfriendly System.Security's exceptions and your application has no idea what to do other than crashed.

Note that if your application are has the "FullTrusted" permission, nothing will matter because CAS will not check any permission when running your assembly.

Declarative Security Check

Basically all declarative security is done though the Permission Attributes . By applying declarative security check to your class or your methods, if the check failed, none of the code will run. For example:

[FileIOPermission(SecurityAction.Demand, Write = @"C:\Documents and Settings\Administrator\Something.txt")]
private void DeclarativeCreateFile()
{
    Console.WriteLine("Prepare to write to Administrator folder");
    CreateFile(@"C:\Documents and Settings\Administrator\something.txt");
    Console.WriteLine("Write completed");
}

Because we used declarative security check to "demand" if we have the right to write files under the Administrator folder, NONE of the code in this DeclarativeCreateFile() will run. When calling this method, you will get an System.Security.SecurityException.

Also, with declarative security, .NET Framework has provided some tool to check if your application can run under certain permission. I am guessing since we uses attributes, the runtime can use reflection to find all the declarative security check.

Imperative Security Check

To me, imperative security is a more refine way to check an assembly permission rights. Here is an example:

private void ImperativeDemandCreateFile()
{
    FileIOPermission writeFilePermission = new FileIOPermission(FileIOPermissionAccess.Write, @"C:\Documents and Settings\Administrator\something.txt");
 
    try
    {
        Console.WriteLine("Prepare to write to Administrator folder");
        writeFilePermission.Demand();
        createFile(fileName);
        Console.WriteLine("Write completed");
    }
    catch(Exception ex)
    {
        Console.WriteLine("Failed before attempting to create file. ");
    }
}

In the above example, if CAS doesn't give permission for this assembly to write to the administrator folder, the "writeFilePermission.Demand()" will throw you an SecurityException.

There are definitively different advantages of using imperative compare to declarative permission. Please refer to http://msdn2.microsoft.com/en-us/library/aa302422.aspx for more details.

Evaluating your Assembly

Since an assembly can belong to multiple code group, how can you tell what permission it has in the end? You can uses the .NET Framework 2.0 Configuration, click on "Runtime Security Policy" and you will see a link "Evaluate Assembly" on the right panel. Click on the link, select a .net assembly in the wizard and it will tells you what permission your selected assembly has.

Conclusion

CAS is very powerful, but yet I feel that it is hard to master it because of its flexibility and complexity.  I guess the only way to master this technology is to apply it in your daily programming routine. Especially when security is becoming a important issue. We can't expect all our user will run our application in Administrator mode. Therefore our application has to handle situations where the application has no permission to access certain resources.

1 comment:

Anonymous said...

Excellent post, I have a problem, I do not have the "Local_Shared_Folder" try to add commands to the Visual Studio and not got anything caspol-machine-addgroup All_Code, etc ... :( Should know that!

Thanks!

E-mail: mascodigo.net@hotmail.com