Writing CAS-Aware Code


At this point, you should have a pretty good idea of what CAS is, how it works behind the scenes of all managed code, and what options you have for administering security policy. This next section will show you some of the various coding techniques that you can employ to not only make your applications aware of security, but to better interact with security policy and CAS.

There are two different ways in which your application can specify which permissions it needs or the permissions that are required of the caller in order to invoke it. You can use an imperative security syntax, which uses specific methods from the security namespace to interact with CAS. The other method you can employ is to use declarative security, specifying code attributes that will interact with the security system through Reflection.

Using Imperative Security Syntax

Imperative security involves creating an instance of the security permission you need before performing the task for which the permission is required. In addition to creating an instance of a single permission, you can create an instance of a permission set that allows you to demand specific sets of permissions from the .NET Framework.

For example, to create an instance of the FileIOPermission class and then issue a demand indicating that all callers on the stack prior to the demand must have at least the amount of privilege indicated in the constructor to the FileIOPermission class, use the following code:

 FileIOPermission fileIo =   new FileIOPermission(     FileIOPermissionAccess.Write, @"C:\SEC\myfile.txt"); fileIo.Demand(); 

To see this in action, you can write a simple console application that performs this action. Before setting up security policy, write the code and see that it executes just fine. Then modify security policy using the earlier instructions to set the permission set of your application to Internet. The Internet zone does not (by default) have permission to access the local file system, so when you run the code under the Internet privilege, you will get a security error.

Another important thing to note is that the Demand() method protects the entire method in which it was invoked. In other words, if that demand fails, no code within the method will ever be called. When a Demand() is compiled, the MSIL is modified so that the permission is checked before the method is invoked. You can verify this by putting a Debug.WriteLine method call before you issue the Demand(). This output will show in the debug window only if the demand passes. If the demand fails, you will see that your code is never executed. This is an important point to remember about protecting entire methods from illegal execution.

Using Declarative Security Syntax

Declarative security works by using code attributes to protect methods and classes from being executed when the permissions of the caller or callers are not sufficient. This can mean demanding that the call stack have sufficient file I/O permission, or it can demand that somewhere on the call stack be the identity of an assembly with a particular public key, or version number, and so on.

To protect a method, you use an attribute like the one that follows. (For a list of the attributes, see the list of permissions. Each permission has its own attribute that can be used in your code.)

 [FileIOPermission(SecurityAction.Demand,    PathDiscovery="C:\\SEC\\myfile.txt")] public void CreateAnotherFile() {   // perform file I/O   System.Diagnostics.Debug.WriteLine(     "Executing CreateAnotherFile"); } 

As with the other test, if you deny your code the capability to access the file system, none of the code in the method protected by the attribute will execute. That is one of the really beneficial features of CAS. If, at design time, you know that your code is going to need several privileges, you can demand them up front. If you don't get the results you want, you can provide the user with a friendly error indicating the reason for failure. This enables you to prevent data loss, break of workflow, and even data corruption due to a security failure in the middle of the application.

TIP

Even if you have the proper using directives for System.Security, if your project doesn't reference the System.Security DLL, all of your demands will appear to pass, even if your code has insufficient privilege to pass.


Blocking Unwanted Clients

Consider the following scenario: You have created a Windows Forms application that you want to be distributed to all of your clients. This application performs several actions that you don't want to be performed by any application but your own. In most circumstances, any .NET programmer could find out all the methods exposed by your application and consume it. This would allow other programmers to use functionality that might corrupt data or circumvent measures that prevent users from using features of an application for which they haven't paid.

Using security demand features, you can write your code in such a way that certain methods in your application cannot be called by client code unless that client code was also written by you or your organization. You can tell that the code was written by you or your organization if the code has a strong name and the public key token is the same for the calling code as it is for your code.

This security demand involves the StrongNameIdentityPermission attribute class. If you protect a class, method, or other member with that attribute, you can control the identity of calling clients; thereby ensuring that only those you want to call your code can call your code.

The first thing you need to do to make this work is get the public key token that you want to require. Remember that the public key token is virtually synonymous with a manufacturer or publisher. If a company is consistent, it will use the same strong name for all of its software, enabling you to write security policy against that manufacturer.

So, if you want all the code in a particular utility library to be available only to your own applications, you will restrict access to that library to only that code with the right public key token.

To get the public key token, use a tool called SECUTIL.EXE. This tool is part of the Framework SDK. Here is a sample invocation:

 secutil -hex -s CASLibrary.dll 

This will display all the strong name information associated with the CASLibrary.dll assembly. The output is as follows (for my sample library; your output will vary with your own assemblies):

 Microsoft (R) .NET Framework SecUtil 1.1.4322.573 Copyright (C) Microsoft Corporation 1998-2002. All rights reserved. Public Key = 0x002400000480000094000000060200000024000052534131000400000100010073F835D64CDBD4 348C6B9EB55C23BEB3B66880512E07602ED508AB038C5AE68AE2A72C0F3F403B08A637667DDBE6F5 DAF2ADC96EFB7BAF6096C220A2F272807B91885FEB436FFBF1455337FDB06F74A44213DBCFB5384B 146AFC0C078E0E336BC96BAE3791CB514FEF3DEBC7DB49E684F002261BEB84E7F6BAE35304F7706A B4 Name = CASLibrary Version = 1.0.0.0 Success 

The public key piece is what we are looking for as publisher identification. To test this security feature, create a new class called PublisherProtected in CASLibrary.dll. The code is shown in Listing 34.1(note that the preceding 0x hex indicator contained in the original string output by secutil has been removed):

Listing 34.1. Identity-Protected Method
 using System; using System.Security; using System.Security.Permissions; namespace CASLibrary {   /// <summary>   /// Summary description for PublisherProtected.   /// </summary>   [StrongNameIdentityPermission(SecurityAction.Demand,   PublicKey="002400000480000094000000060200000024000052534131000400000100010073F835D64C" +   "DBD4348C6B9EB55C23BEB3B66880512E07602ED508AB038C5AE68AE2A72C0F3F403B08A637667DDBE6F5" +   "DAF2ADC96EFB7BAF6096C220A2F272807B91885FEB436FFBF1455337FDB06F74A44213DBCFB5384B" +   "146AFC0C078E0E336BC96BAE3791CB514FEF3DEBC7DB49E684F002261BEB84E7F6BAE35304F7706AB4")]     public class PublisherProtected     {       public PublisherProtected()       {       }       public string GetMessage()       {         return "This message is from a protected method.";       }     } } 

Execute this code from an application that has been signed with the same strong-name key pair file to see that the application works properly and when you try to call GetMessage everything works as it should.

However, to ensure that unwanted consumers of your code cannot use it, create a new assembly that is signed with a different strong-name key pair file. When you try to execute this method, you will get a security exception.

As mentioned before, these attributes are evaluated before code within any protected method is executed. This means that if a protected class requires a public key identity from its callers, no property or method of that class can be accessed by any code that doesn't have the appropriate public key.



    Visual C#. NET 2003 Unleashed
    Visual C#. NET 2003 Unleashed
    ISBN: 672326760
    EAN: N/A
    Year: 2003
    Pages: 316

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