• Advertisement
  • entries
    146
  • comments
    436
  • views
    198351

Code Access Permissions

Sign in to follow this  

162 views

I figured that since you are all intelligent individuals that you would like to know how to write secure code in .Net without requiring the use of a separate assembly. It's actually quite simple. First of all, you should do some research into the CodeAccessPermission class, which is a rather handy class. From this class one can inherit their own permissions, and hence allow highly controlled access to the methods they wish to expose to external assemblies (or even internal assemblies). A simple example follows

using System;
using System.Security;
using System.Security.Policy;
using System.Security.Permissions;

namespace CodeSecurity {
[Serializable]
public sealed class MyPermission : CodeAccessPermission, IUnrestrictedPermission {
public MyPermission(PermissionState state) {
if (state != PermissionState.None && state != PermissionState.Unrestricted)
throw new ArgumentException("Invalid Permission State");

this.state = state;
}

public override IPermission Copy() {
return new MyPermission(state);
}

public override void FromXml(SecurityElement elem) {
if (elem == null)
throw new ArgumentNullException("elem");
if (!elem.Tag.Equals("MyPermission"))
throw new ArgumentException();

string text = elem.Attribute("class");
if (text == null)
throw new ArgumentException();
if (text != this.GetType().FullName)
throw new ArgumentException();

state = (PermissionState)Enum.Parse(typeof(PermissionState), elem.Attribute("state"));
}

public override IPermission Intersect(IPermission target) {
if (target == null)
return null;

MyPermission permission = target as MyPermission;
if (permission == null)
throw new ArgumentException("Invalid target, expected MyPermission");

if (IsUnrestricted() && permission.IsUnrestricted()) {
return new MyPermission(PermissionState.Unrestricted);
}

return null;
}

public override bool IsSubsetOf(IPermission target) {
if (target == null)
return false;

MyPermission permission = target as MyPermission;
if(permission == null)
throw new ArgumentException("Invalid target, expected MyPermission");

if (IsUnrestricted()) {
return permission.IsUnrestricted();
}

return true;
}

public override IPermission Union(IPermission other) {
if (other == null)
return Copy();

MyPermission permission = other as MyPermission;
if(permission == null)
throw new ArgumentException("Invalid target, expected MyPermission");

return new MyPermission(state | permission.state);
}

public override SecurityElement ToXml() {
SecurityElement elem = new SecurityElement("MyPermission");
elem.AddAttribute("type", this.GetType().FullName);
elem.AddAttribute("state", state.ToString());
return elem;
}

public bool IsUnrestricted() {
return state == PermissionState.Unrestricted;
}

private PermissionState state;
}
}




This is a simple example, mind you, and quite trimmed down too. But it will serve our purposes. Next we need a method that requires this permission to execute

private static void DangerousMethod() {
MyPermission permission = new MyPermission(PermissionState.Unrestricted);
permission.Demand();

//do something dangerous
Console.WriteLine("\t\tDoing something dangerous.");
}

We also should have a method that doesn't require this permission state, just for testing purposes

private static void NotDangerousMethod() {
Console.WriteLine("\t\tDoing something safe.");
Console.WriteLine("\t\tSqrt(2) = {0}", Math.Sqrt(2.0));
}

Finally we need a method that will execute these two methods, one that should call the safe method first, and then the dangerous one (that way we can assert that the safe method does actually get called, and doesn't just get blown away by the exception we hope to see...

private static void InsecureMethod() {
Console.WriteLine("In insecure method.");
Console.WriteLine("\tCalling safe method:");
NotDangerousMethod();
Console.WriteLine("\tCalling dangerous method:");
DangerousMethod();
}

Well, that's all fine and dandy, now how about some code to call this method

MyPermission p = new MyPermission(PermissionState.Unrestricted);

p.Deny(); //can no longer call methods that require MyPermission rights.

try {
InsecureMethod();
} catch (SecurityException) {
Console.Write("================================================================================");
Console.WriteLine("Method could not do something dangerous.");
Console.Write("================================================================================");
Console.WriteLine();
}

CodeAccessPermission.RevertDeny(); //can now call methods that require MyPermission rights.

InsecureMethod();




Well now, if you execute this set of code, you will quickly see that yes, indeed, the exception does get called when it tries to call the dangerous method. We also see that when the deny is removed, that the insecure method can be called successfully. Finally there is the issue of allowing only that permission, for this we do something slightly different.

private static void OnlyMyPermissionAllowedMethod() {
Console.WriteLine("In my permission only method.");
Console.WriteLine("\tCalling safe method:");
NotDangerousMethod();
Console.WriteLine("\tCalling dangerous method:");
DangerousMethod();
Console.WriteLine("\tCalling method that is not allowed:");
System.IO.File.OpenWrite("test file.txt");
}

This method requires MyPermission rights, along with access rights to the file IO functions. The following chunk of code restricts all rights except those of MyPermission, and calls this method.

p.PermitOnly(); //Now only MyPermission access is allowed.

try {
OnlyMyPermissionAllowedMethod();
} catch (SecurityException) {
Console.Write("================================================================================");
Console.WriteLine("Method could not access restricted function.");
Console.Write("================================================================================");
Console.WriteLine();
}

CodeAccessPermission.RevertPermitOnly(); //Previous permission states are restored.




Again, if you run this code you will note that it throws when you attempt to call the File.OpenWrite method. This is as expected.

As you can see, permissions are quite powerful, and can allow you to control what execution permissions code has at a very fine-grained level. This sounds perfect for a scripting system...doesn't it?
Sign in to follow this  


2 Comments


Recommended Comments

This is exactly what I was looking for. Thanks a lot, Washu.

As far as using it for scripting, you'd just have to set the permission set before invoking any methods within it. And take them off after you invoke the method. Would it be worth it to make a whole new AppDomain and then set the permissions on that? Then you wouldn't need to set and take off the permissions because they'd be unique to that AppDomain. Or is that going a little overboard?

I'll let you know how far I get as to implementing it for scripting. Thanks again!

Share this comment


Link to comment
Well, that really depends. YOu know, you don't have to create the permission each and every time you want to assert it, you can just create a single instance and store it. Then you can demand it, and deny it easily enough. The thing is, with a seperate app domain you get a few bonuses:

1) You can unload the scripts when done with them. This means that unused scripts don't stick around in memory.
2) Security is much easier to achieve (you just give the app domain the execute permissions you want, and nothing more, end of story).
3) It's probably a bit easier to implement.

However, it does have some disadvantages...
1) Speed. You will have to use remoting to access anything in the other application domain, this is required for both directions (so, remoting to call the script, and remoting for the script to access game information).
2) remoting can get quite complex for complex objects. It isn't always easy to tell when you should pass something as a reference type or as a copy type, and complex types can be particularily tricky.

In the end, experiment and see which meets your needs best.

Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement