KnowDotNet Visual Organizer

Code Access Security and .NET

by William Ryan
Print this Article Discuss in Forums

Just about everything has changed in one way or another in .NET, and security is no different.  Before I worked at my current job, I had done a fair amount of .NET work but most of our stuff was done the old school way.  We deployed to external customers exclusively, and used traditional install scripts for deployment.  When I changed jobs, most of my beginning work was done internally.  And instead of using install scripts, we put the .exe out on a network share and just created shortcuts.  So the first time I tried this, I got a Security Exception and my boss had to come show me how to adjust the security policy.  At the time, I thought it was unnecessary, but after I started understanding .NET and the new security paradigm, I learned to appreciate it.  Think about it for a second, features like No Touch Deployment are truly revolutionary, but if handled recklessly, they could enable a malcontent to put an early end to your career.

To understand Code Access Security, you first need to have a good understanding of Windows Role Based Security.  If you have no familiarity with it, I'll run through it briefly, but it's a complex topic and the subject of entire books, so you'll probably want to read up on it on your own.

In the old days, you would grant one permissions to network resources on a per case basis.  Hence, if you have a user that had access to say 20 different things on your network, you'd add the user and grant each individual permission.  If you had 50 users that all needed the same access (typical of a department or business unit), you'd have a lot of adding to do. With Role based programming, you create roles and grant the role permissions to a resource.  You can have virtually unlimited roles and people can and often are members of different roles.  So for instance, let's say that you had 10 people in Finance that could access all financial records.  Finance also needed access to a printer.  Let's say that everyone in the Help Desk area needed that printer to.  You could create a role and grant it access to the printer.  You could then create two other roles, Finance and Help Desk and add them to the printer group.  They would also have permissions specific to their own roles, but they could share this role by virtue of dual membership.  If you've ever done any database or network administration, you know how powerful and convenient this paradigm is (then again, you probably don't need me to explain it to you).

Code Access Security is a supplement to this.  Programming Guru Paul Kimmel uses a great analogy to describe the interaction of Windows and Code Access Security- Federal vs. State Governments.  In his analogy, the Federal could ban something, say Marijuana.  States wouldn't be at liberty to legalize it (and if they did, the Feds could arresnt any citizen of the state caught with it).  However, the Federal Government could allow the sale of Alcohol.  But states or municipalities could ban it.  As such, Federal law supercedes State law in the same way that Windows Security Policy superecedes Code Access security.  However, Code Access Security can be more restrictive than Windows Security.  For example, let's say you had an evil Evil Network Administrator that didn't allow you to write to the registry and all sorts of other evil stuff implemented through Windows Group Policy.  Nothing you do with Code Access Security will allow you to write to the registry.  However, he could grant access to certain registry keys, and you could restrict writing to those keys through your code via Code Access Security.

Now, the first thing to realize is that .NET code is Managed Code and vice versa.  You can run unmanaged code via COM Interop Services and the System.Runtime.Interopservices namespace, but the unmanaged code is running through a managed layer.  And since you can control anything that runs in the context of your app, you can prohibit anything and allow anything that is allowed by Windows Policy.

The next thing to remember is that not all code is equally trustworthy.  Sure, I have written my share of recursive loops with no exit condition and all sorts of other stuff, but my company trusts my code a lot more than it does something pulled down from the internet.  As such, there are trust zones that you can allow or disallow.  Obviously the less you know about the creator, the less you should trust it.  

One of the really interesting things I came across when researching security is what can be done with Reflection.  Someone, even someone internally, could take a safely kept .dll and decompile it with Ildasm.exe.  They could learn about the assembly, and using Shadowing and Overrides to completely change the way an existing assembly behave.  (I hope all of those programmers who constantly tell me how worthless Sealed methods are b/c they block inheritance).
Microsoft has provided a great discussion on security practices which I think you'll find enlightening.

Ok, enough background information, I'm going to move into Declarative and Imperative Security.  If you want to secure your app via code, you have two basic ways to do it.  You can manually write your own checks and compare them to a database or a registry value or similar mechanism.  In the past, this is the primary way you would implement such a mechanism.  So, if you only wanted Managers to be able to print, you'd write your code to check your database before enabling the print button and respond accordingly.  This mechanism still works and definitely has its place in .NET.  However, this approach has some serious drawbacks.  For one thing, it doesn't take advantage of Role based security, and while you can mimic it with your 'own' groups, there's going to be a large amount of duplication between your security and the company's.  Moreover, you may not be there when an loose cannon gets fired and they may still be able to use your app to do something.  Perhaps the guys in Networking don't know how to delete and add users to your system (I know I don't know how to do a lot of their jobs, and they are usually to busy keeping the network up and running to worry about doing my job).  Moreover this approach adds to your code.  Think about how much it would take if you wanted to implement Roles that could be added to'd have quite a few database tables or a bloated registry really quickly.  Finally, what if someone else wanted to use your .dll?  Perhaps they wanted to but it, but didn't want to implement your security scheme.  How could they override or disable this if all they had was your .dll?  Perhaps they could, but it sure wouldn't be fun.

That's where Attributes and Declarative Security come into play.  Whereas Imperativie Security shines when you only will know things at runtime, Declarative lets you know it beforehand.  Now, I've mentioned that Declarative Security is implemented with Attributes but what does that mean?  If you look at the article I just reference, you'll see that one possible attribute you can use is Obsolete.  There are multiple Security Permissions in the framework, but let's take a look at one of them in particular, FileIOPermission

So let's say I have the following code snippet:

private void btnReadFile_Click(object sender, System.EventArgs e){
    catch(System.IO.IOException ex){
        Debug.Assert(false, ex.ToString());

We could mark this code with a Security Attribute:

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

So what did that just do?  It ensures that you will determine whether the code has enough access granted to it to ensure access to operate.  There are 4 different SecurityAction elements which you can apply:

RequestMinimum - Checks if you have enough permission to execute properly
RequestOptional - This can check if additional permissions are required, in the same way you can pass in Optional Parameters in VB.NET.  In order to use this, you need to use wrap everything in a try catch block in the case that there isn't enough permission
RequestRefuse - This can stop the code from executing by limiting what it can do
Demand - Everything that calls this block must have adequate permissions to execute

The first time I saw this, I thought, So what?  Won't I just throw an exception anyway if I don't have permission?  Well, it depends.  You see, an app that we wrote internally could in fact have the permissions to do this.  But if someone used the Shadowing method or similar method and included a reference to my class library in their app, my code could possibly open this file even though the program using my app doesn't have the permissions to do it.  By restricting what consumers of my .dll can do, I can exert tremendous control over it.  In a paradigm where everything is run from a local machine and everything is written internally, this isn't a big concern.  But in n-Tier apps where .dlls can be consumed from multiple programs, you  can grealy reduce the chances of someone doing something you don't want with your code libraries.

.NET has a lot of power in the classes that it provides, but you are free to create your own classes and really fine tune your apps.  Some security strategies for example, don't want to let would be hackers know that they are discovered.  So you could use a similar strategy to notify security personnel in the case something fishy is going on.

So, in a nutshell let me summarize a few of the benefits of Declarative Security:

* You can use Attributes to define your security policy
* You don't need to run the code to evaluate what is allowed.  Everything can be defined before you ever start the exe
* You don't have to invoke the method for the security check to take place.  It happens before any line of code is ever executed in the code block
* You can set policy for an entire class by defining an  attribute for that class.  You don't need to do it individually for each method.

In a nutshell, this security model is very powerful and very easy to use.  Moreover, it lets you really fine tune your applications to accomplish just about anything you want in the context of security.

Writing Add-Ins for Visual Studio .NET
Writing Add-ins for Visual Studio .NET
by Les Smith
Apress Publishing