Author Topic: C# Code Access Security  (Read 7511 times)

Offline admin

  • Administrator
  • Sr. Member
  • *****
  • Posts: 296
    • View Profile
C# Code Access Security
« on: September 12, 2010, 01:51:45 PM »
In today's fast growing Information Technologyworld, security is a major concern. Security is important not just toauthenticate users but also to authorize their actions. Common businessscenarios where we need more control over security are

1. To restrict the user's access to the application, based on their identity
2. To restrict the user's access to protected resources and certain functions of the application.
3. To verify the identity of the calling program, to check if the caller is trusted or not.

In this article I will be taking a close lookat .NET Security. Code Access Security addresses these issues. Thefoundation of CAS is the Permission Object.

Download codeaccesssecurity.zip from attachments

Permission:
CLR requires that the code should have required permissions to accessthe protected resources. For example if the code has to read from anenvironment variable or write information to a file, the code shouldhave enough permission to perform these operations. Permission Objectsare used to enforce these security issues. Lets take a look at whatkind of Permission Objects are available in .Net and how we can usethem to secure our application. There are three different kinds ofpermission objects, each serving a specific purpose: IdentityPermission, Code Access Permission and Role Based Security Permission.

Identity Permission:
CLR validatesthe identity of the assembly provided to it by the loader or host. Thehost can be a server host (Asp.Net) or a shell host (command line). Theidentity, called the Evidence, can be a strong name(StrongNameIdentityPermission), originating Zone that is Intranet,Internet or Trusted site (ZoneIdentitypermission), publishers digitalsignature (PublisherIdentityPermission), originating URL(URLIdentityPermission) or originating website(WebSiteIdentityPermission). I will explain in detail with examples theformer two

StrongNameIdentityPermission:
Thispermission object identifies the caller with a strong name. In order tohave a strong name for your assembly, the code should be signed by akey pair. .Net provides the utility, sn.exe, to generate a key pair. sn-k KeyPairFileName.snk Once the keyfile is generated, you can place thefollowing line of code in AssemblyInfo.cs [assembly: AssemblyKeyFile(@"..\..\KeyPair.snk")] The above line will make sure that the assemblyis signed with a strong name.

Let us look at an example to understand how wecan use StrongNameIdentity Permission to identify the caller. Create aconsole application called TestPermissionObjects.exe. The assembly issigned with a strong name as shown above. We can demand the strong nameidentity permission in our component using the public key counter partof the key pair generated.

Code: [Select]
public bool TestStrongNameIDentityPermission(string strongname,string version)
{
try
{
byte[] publickey = { 0, 36, 0, 0, 4, 128, 0, 0, 148, 0, 0, 0, 6, 2, 0, 0, 0, 36, 0, 0, 82, 83,
65, 49, 0, 4, 0, 0, 1, 0, 1, 0, 45, 25, 102, 36, 141, 31, 69, 83, 150, 31, 81, 170, 101, 131,
2, 136, 254, 120, 34, 55, 22, 245, 242, 91, 151, 25, 32, 206, 224, 156, 198, 240, 123, 2, 52,
230, 50, 196, 88, 84, 15, 86, 232, 53, 147, 140, 161, 64, 59, 200, 217, 15, 237, 100, 152, 230,
19, 148, 160, 187, 218, 36, 45, 168, 159, 92, 13, 58, 46, 43, 195, 106, 134, 98, 68, 226, 206,
166, 236, 88, 33, 160, 82, 254, 165, 38, 19, 22, 64, 28, 247, 127, 175, 225, 92, 214, 63, 102,
232, 124, 196, 242, 22, 144, 31, 64, 92, 248, 164, 148, 109, 130, 18, 103, 206, 177, 173, 104,
190, 221, 164, 102, 34, 150, 110, 25, 127, 189 } ;
// publickey can be extracted using utility secutil.
// secutil -strongname AssemblyNameWithFulpath
StrongNamePublicKeyBlob publickeyblob = new StrongNamePublicKeyBlob (publickey);
System.Version ver = new Version(version);
StrongNameIdentityPermission sip = new StrongNameIdentityPermission(publickeyblob,strongname,ver);
sip.Demand();
return true ;
}
catch(SecurityException se)
{
Console.WriteLine ("Identity Permission Failed — Strong Name " + strongname + "–version — " + version );
return false;
}
}

Any client that is calling the above method ofthe component should have the strong name, key pair and correct versionotherwise the call to this method will throw a Security Exception.

ZoneIdentitytPermission:
Thispermission object identifies the caller with the zone the calloriginates from. Defined Security Zones are Internet, Intranet,MyComputer, NoZone, Trusted, and Untrusted. Code can demandZoneIdentityPermission to ensure that the caller is from the specifiedzone. The following example explains how to use ZoneIdentityPermissionobject to ensure that the callers are from the local computer, that isfrom the MyComputer zone.

Code: [Select]
public string TestZoneIdentityPermission()
{
ZoneIDentityPermission zip = new ZoneIdentityPermission(SecurityZone.MyComputer)
zip.Demand();
//The line below will succeed only if the calling code is from the zone MyComputer.
// If the same component is called from Intranet the call will fail.
StreamWriter sw = new StreamWriter("TestPermission.txt")

sw.write("Sucess ZoneIDentityPermisson");

sw.close();
}

PublisherIDentityPermission:
This permission object identifies the caller with the Digitalsignature. The caller should be signed with a Digital Certificate.

URLIdentityPermission:
This permission object identifies the caller with the URL from which the call originates.

SiteIdentityPermission: This permission object identifies the caller with the website from which the call originates.

Code Access Permission: Identifying the caller using identity permission is not adequate tosecure an application. Various resources like file, environment,variables and message queues should be protected along with thecritical operations that the code performs. These Security policies canbe enforced using CodeAccessPermission. There are variousCodeAcessPermission objects available in .NET such as FileIOPermission,EnvironmentPermission and EventlogPermission. For a list ofCodeAcessPermission refer tohttp://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguidnf/html/cpconidentitypermissions.asp

CodeAccessPermission object restricts accessto the protected resources, identifies if all the callers in the callstack have sufficient permission and provides functionality to createthe object from xml. These are basically the implementations of theinterfaces IstackWalk, Ipermission and IsecurityEncodable.IstackInterface implementation in CodeAcessPermission objects ensuresthat all callers in the hierarchy have enough permission to access theprotected resources. IPermission interface has the methods: Demand,Copy, Union, IsSubsetOf and Intersect. Every CodeAccessPermissionobject has this interface implemented and the client can call theDemand() method of the permission object to make certain that therequested permissions are available.

CodeAccessPermission can be implemented
in two ways. One is Imperative syntax and the other is Declarative syntax.

Imperative Syntax:
You can protectaccess to the resources and functions by creating an instance ofappropriate permission object and demanding the permission. Lets take alook at FileIOPermissionObject and how we can confine access to filesand folders.

Code: [Select]
public void TestFileIOPermission(string path , string filename)
{
try
{
FileIOPermission fip = new FileIOPermission(FileIOPermissionAccess.Read , path);
fip.PermitOnly();
StreamWriter sr = new StreamWriter (path +"\"+ filename);
sr.WriteLine ("FileIOPermision success");
sr.Close();
}
catch(SecurityException se)
{
Console.WriteLine (se.StackTrace);
}
}

« Last Edit: September 12, 2010, 01:54:32 PM by admin »

Offline admin

  • Administrator
  • Sr. Member
  • *****
  • Posts: 296
    • View Profile
Re: C# Code Access Security
« Reply #1 on: September 12, 2010, 01:58:20 PM »
Declarative Syntax:
You can controlaccess to resources and functions by placing a Security Attribute atMethod, Class or Assembly Level. Security information defined usingattributes are placed in the metadata of the code. EachCodeAccessPermission has its corresponding Security Attribute. EachSecurity Attribute takes at least SecurityAction as parameter.SecurityAction enumeration can take values depending on where thesecurity is enforced. For example, RequestMinimum is supported only atAssembly level. Let us take a look at the following example, whichrefuses access to winnt folder.

[assembly: FileIOPermissionAttribute(SecurityAction.RequestRefuse, "c:\winnt")]

Imperative Syntax won�t allow the user torequest permission as opposed to Declarative syntax where you canrequest the permission.

PermissionSet:
PermissionSet is a set of Permissions .You can group the permission andadd it to PermissionSet. PermissionSet implements the same IpermissionInterface. Security calls on a permission set will in turn make callsto permission object of the permission set. For example making a callto perform Deny() on permission set will deny access to permissionobjects that are members of the Permission set. The following exampleexplains the use of Permission set

Code: [Select]
public void TestPermissionSet()
{
PermissionSet ps = new PermissionSet(PermissionState.None) ;
ps.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read ,"c:\C#") );
ps.AddPermission(new EnvironmentPermission(EnvironmentPermissionAccess.Read ,"TEMP"));
ps.PermitOnly();
Console.WriteLine(Environment.GetEnvironmentVariable("TEMP"));
Console.WriteLine(Environment.GetEnvironmentVariable("PATH"));
}


The above function will throw a SecurityException while trying to access the environment variable �PATH� whichis not granted permission.

You can create your own NamedPermissionSet bygrouping the desired pemissions. These PermissionSets can then be addedto codegroup, which will be interpreted by CLR while computing thepermission. (Codegroup — Each code belongs to a certain group based onthe membership condition. Code that satisfy those conditions become amember of the group. Each group has a permission set associated withit. .Net CLR computes permission based on policy, group and associatedpermission set.). The following link gives a detailed explanation aboutcomputing permission and codegroup attributes.http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguidnf/html/cpconpermissions.asp

Let us take a look at a pre-defined permissionset LocalIntranet, which has the permission to execute an assembly,read the environment variables TEMP, TMP and UserName (For otherpermissions of LocalIntranet please refer to security.config file underCLR install directory. Or you may usec:\winnt\Microsoft.net\V*\Framework\bin\ msccorfg.msc). The followingcode, a sample WindowApplication will throw an exception with thePermissionSet LocalIntranet.

Code: [Select]
private void TestLocalIntranetZonePermissionSet()
{
try
{

Console.WriteLine("Environment Variable UserName : " + Environment.GetEnvironmentVariable("USERNAME"));
Console.WriteLine(Environment.GetEnvironmentVariable("PATH"));
}
catch(SecurityException se)
{
Console.WriteLine ("Permission Error — can't read Environment Variable PATH");
}
}

Change the permission set associated with zone MyComputer from FullTrust to LocalIntranet.
caspol -chggroup 1.1 -zone MyComputer LocalIntranet

After performing this change, when you execute the exe file, you will get a Security Exception.

You may reset the security back to defaultsecurity policy using caspol -reset. You can also change the permissionset back to Fulltrust using
caspol -chggroup 1.1 -zone MyComputer FullTrust.

CustomPermission:
You can createyour custom CodeAccessPermission by inheriting fromCodeAccessPermission class. This in turn has the implementations ofIpermission Interface and IstackWalk . Since this derives fromCodeAccessPermission , your custom CAP object will also verify that allthe callers in hierarchy have enough permission. Once you have definedyour custom CodeAccesPermission class, you can demand permissions inyour code in a manner similar to other CodeAccessPermission objects.Please refer to the following link for detailed information on creatingyour own Code Access Permission.http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguidnf/html/cpconpermissions.asp

Role Based Security:
Applicationshould allow access to the critical information and critical operationsonly to authorized users. Users are authorized based on the informationprovided by the user. Access to the resources can be restricted tousers of any group, only to specific group or to all the users of acertain group. .Net defines Principal as the combination of identityand group or role. Identity is nothing but a Windows User(WindowIdentity), userid (GenericIdentity) or it can be custom (customidentity object that implements Iidentity Interface). .Net alsoprovides WindowsPrincipal and GenericPrincipal object . You can defineyour own Principal object by implementing IPricipal Interface. RoleBased security is described in detail athttp://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguidnf/html/cpconnamedpermissionsets.asp

The source code along with this article hasthe implementations of IIdentity and Iprincipal interfaces to defineCustom Identity and Custom Principal.

Note: Custom CodeAccessPermission will checkfor permissions of all the callers in hierarchy by default because ofthe implementation of IStackWalk interface. If you prefer not to checkthe permissions of the callers in code stack, you may implementIpermision interface to define custom permission class.

Let us define a custom authentication scenario where we can use custom permission, custom identity and custom principal objects.
a) Gather Evidence ie Userid and password from the user
b) Authenticate against the data store which can be a database, LDAP, etc
c) Create Identity Object using CustomIdentity class (please see the source code attached)
d) Create Principal Object using CustomPrincipal class
e) Set the Principal as Thread.CurrentPrincipal.


By Setting Principal as Thread.CurrentPrincipal, Princip
al is available at any time by accessing

Thread.CurrentPrincipal property.

Code: [Select]
Public void TestCustomPermission()
{
CustomIdentity ci = new CustomIdentity(�TestUser� ,�TestRole�);

CustomPrincipal cprincipal

CustomPermission cp
Cp.Demand();
}


The above code demands the identity to be TestUser and Role to be TestRole.

Let us take a look at Demand() method of CustomPermission Object.

Code: [Select]
public void Demand()
{
if ( ( Thread.CurrentPrincipal.Identity.Name == this.userid ) & ( Thread.CurrentPrincipal.IsInRole(this.role ) ) )
{
Console.WriteLine("CP…Sucess");
}
else
throw new SecurityException("Custom Permission Denied");
}

Demand() method will fail if the provided credentials are not sufficient. Note: Attached Sample Code has implementations of Ipermission and IIdentity and Iprincipal.

Conclusion:
.Net Security has predefined permission objects which are highly flexible to use and can beextended to address custom permissions. Have fun in securing yourapplication!