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.
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
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.
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):
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.
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.