Thursday, June 17, 2010

.Net Security

The .NET Framework includes a simple but very flexible identity-based security mechanism. By using it, you can exercise very fine-grained control over who is allowed to use your programs and which functions those users can perform. The key is a detailed understanding of the Principal and Identity objects.


 
The Microsoft .NET Framework provides a robust and flexible security infrastructure that can be split into two sections:
 1. Code access security
 2. Identity-based security.

 
The code access security (CAS) model focuses on code identity instead of user identity. Using CAS, you set policies and permissions on assemblies according to their publisher or where they were loaded from, for example. The user identity of the hosting process is irrelevant in the permission granting logic.

 
Compared with CAS, identity-based security represents a classic approach with which most programmers are confident. However, you'll need to master some important concepts to get the most from the .NET Identity Based security infrastructure:

Identity-based Security Important classes are:

 
  1. Identity
  2. Principal objects

 
The .NET Framework abstracts the concepts of user and roles, making them independent of the underlying Windows platform. .NET identity-based security relies on two simple concepts: Identity objects and Principal objects.

 
Identity object:
 
An Identity object is basically a user account. Any .NET class implementing the IIdentity interface is a valid Identity object to use in .NET authorization mechanisms. IIdentity exposes three simple properties: AuthenticationType, IsAuthenticated and Name.

 
The .NET Framework comes with four Identity classes out of the box:

 
  • WindowsIdentity
  • FormsIdentity
  • PassPortIdentity
  • GenericIdentity

 
The Generic Identity class is provided to ease the development of custom authentication mechanisms, but you can define your custom Identity class from scratch implementing IIdentity because there is no significant code you inherit from the GenericIdentity class.

 
You can match a .NET identity with a Windows Identity—that's what WindowsIdentity is for. (Later, you'll see how to do that.) The important point is that nothing makes a Windows Identity different from other Identity objects, as far as .NET is concerned.

 
The standard .NET authorization mechanisms are designed to accept and work with any kind of .NET Principal and Identity objects, totally oblivious of the underlying OS.

 
Of course, you can't bypass OS-related security checks. When you access an NTFS-protected file or any kind of resource that the OS is aware of, Windows triggers its authorization mechanisms against the identity of the process that is trying to access the resource (or eventually against the identity the process is impersonating).

 
Principal object:
A Principal object is a holder for all the roles the user belongs to (according to the active authentication mechanism). Again, any .NET class implementing the IPrincipal interface is a valid Principal object. The IPrincipal interface exposes the Identity property (returning the underlying Identity object) and the IsInRole method.

 
The .NET Framework class library comes with two Principal objects: WindowsPrincipal and GenericPrincipal. When a WindowsIdentity-WindowsPrincipal pair is used, the Principal role list is built using the Windows groups the Windows user belongs to.
 
Permission objects – define permissions:

For user base security – PrincipalPermission Class is used.: IPermission
For CAS – CodeAccessPermission Derived classes is used. : IPermission

IPermission Interface – Demand method – verifies if caller higher on the stack trace have not been granted permission specified by the permission object.

User Based Security:

 
1. Identity Objects : represents the identity of the user. Implement IIdentity Interface ( Authentication type, IsAuthenticated, Name of user)
  1. GenericIdentity – represent the identity of the user authenticated by custom authentication.
    1. Idenity gid = new GenericIdentity(Auth type, IsAuth., Name of user)
  2. WindowsIdentity – represent identity of the user authenticated by windows authentication.
    1. Idenity wid = new WindowsIdentidy(User token, AuthType., windows Account Type, IsAuth)User token is of IntPtr data type which refers to a user account token and can be a pointer or a handle.This can be obtained via unmanaged win32 APIs such as logonUser
    2. Windows identity object can also be obtained using GetCurrent and GetAnonymous methods of it’s class.
  3. FormIdentity
  4. PasssportIdentity
2. Principal Objects: (System.Security.Principal) these objects contains the identity and role of the logged in user. Implements
  1. IPrincipal ip = Thread.CurrentPrincipal.
    1. IPrincipal interface
      1. IIdentity – represents the identity object associated with principal object.
      2. IsInRole – take string role as param and verify if principal object roles collection contains given role.
    2. GenericPrincipal Object
      1. Constructed using GenericIdentity and Roles array. New GenericPrincipal(myGenericIdentity, srint() Roles)
    3. WindowsPrincipal Object 
      1. Constructed by windows identity object as roles for particular identity are already mapped in windows
Implementation:

  • By default principal policy on appdomain is GenericPrincipal so if authentication mode is windows we need to explicitly set the principal policy to windows else we wouldn’t get the user information we interested in. Also we need to cast the generic principal object retrived from Thread.CurrentPrincipal to windows principal object.
  • Either user if statement to check role and name as required like
    • If Principal.idenitty.name.Equals(“Gauri”) …..
    • If Principal.Isinrole(“Admin”) ..
  • Or use PrincipalPermission object demand method
    • Pp = New PrincipalPermission(username , Role)                                                         Pp.Demand() – this line verify the username and role from principal objectr against username and role provided in the principalpermission object and if not verified will throw SecurityException.
  • Or use Declarative Approach
    • [PrincipalPermission(SecurityActin.Demand,Name = “Gauri”] – this method can only be executed by Gauri.
CAS:
Cas is all about setting or getting the trustworthiness of an assembly.i.e What code you can trust and to what degree. Same application can have assemblies with different trust level

 
Different degree of trust can be set at – assemble level,class level or even at method level.

 
CAS can only work with verifiable type safe code. i.e CLS must be able to verify the type safety of assemble when it is loaded into the memory. So if PInvoke is use to load an assemble CAS wouldn’t work.

Security in .net is based on two fundamentals:
  1. Type safety of managed code: It means
    1. Bound checking is performed on all data types
    2. Prevent inappropriate or dangerous type conversion.
    3. Prevents direct memory manipulations.
  2. Vigilance of CLR
JIT compiler performs code verification by examining IL of each method and meta data for any risky operations. It verifies type safety and any unsafe operation like memory manipulation so even if any bad compiler is used to generate assembly or some one injected malicious code in IL it will be verified by JIT at run time.
If code is granted SkipVerificaiton – then it is possible to bypass verification process.
Not all .net languages generate verifiable type safe code. Vb.net does always, C# does if unsafe is not used.
PEVerify.exe can be used to test if code is verifiable type safe.
Verifiable means some features according to JIT verification definition.
SkipVeification assemblies can only execute if they are fully trusted.

 
Denying and Demanding the permission
Using good code by some malicious client is called luring attack.

Using Demand code can verify if it has all permission required to execute before starting the execution.

 
Use deny to limit the permission required for its execution – this is used to avoid luring attack

 
Stack Walking – if a method demand certain permission CLR check all it’s caller from immediate caller to up in the hierarchy for the required permission.

Working
Security permissions are configured not at assemble level but at code groups level.
There are four levels:
  1. Enterprise level
  2. Machine level
  3. User level
  4. Appdomain level
Except appdomain all levels are configured and managed administratively but appdomain can be cofigured programmatically at run time only.

Lower level can not have more liberal permission than higher level.

 
Membership condition categorize the assemblies into different code groups.

 
Permission set define the permission granted to particular code group.

 
Assemble can fall in more than one group. Then permission can be evaluated by intersection of permissions on that groups.

Each code group define Membership condition and has only one permission set. One permission set can define number of permission.

 
Configuring tools –
  1. Mscorcfg.msc – for manual configuration.
  2. Caspol.exe – for automated scripting
Policy Assemblies: define permission and member condition that used by security engine for permission evaluation. –they are fully trusted and digitally signed and deployed in GAC For custom permission or custom member ship condition you need to add custom assembly in policy assembly so basically they are security infrastructure assemblies.

Some member ship conditions are:
  1. Publisher
  2. Site
  3. Strong Name – providing digital signature
  4. URL with protocol.
  5. Zone
  6. ….
     
Implementation:

Imperative:

 
  1. Using evidence classes (System.securityPolicy)
  2. Using derived codeAccessPermission classes.

 Declarative:
  1. Get Evidence object, get it enumerator and loop thru it’s attributes. Like - Zone, URL, Hash, Strong Name, Site…
 Evidence ev = appdomain.CurrentDomain.Evidence

 Ienumerator en = ev.GetEnumerator();

 While en.MoveNext

 Object item = en.Current

 If Item.StrongName = “MyAssembly”

 Do smth Secure

 
2. Using CodeAccessPermission Classes – in this construct a derived codeaccesspermission class and call it’s method like demand,deny or assert to automatically validate the permission.There are many derived classes for specific purposes like

 
  1. webPermission
  2. FileIOPermission
  3. UrlIdentityPermission
  4. ZonalIdentityPermission

 Imp method of this class are:

 
  1. Assert: it request the permission starting from calling function to down the stack trace if all code down the stack trace will have the permission as requested by assert calling object.Even if higher heriarchy denied the permission assert can be used to get it for some operations. Only one assert is allowed per stackframe else security exception is thrown.Use cautiously as it may introduce luring attack.
  2. Demand: It is used to verify the that calling method have the permission it does this by performing the a stalk walk checking the permission of each method found higher on the call stack
  3. Deny: use to restrict the permission down the stack. Only one deny per stack frame. UrlIdentityPermissin uip = new UrlIdentityPermissin(file://c:/./....)                                                Uip.Demand() 
  4. Declaritive: 
    1. [UrlIdentityPermission(SecurityAction.LinkDemand,Url=”file://c:/../...”]               [( )]

 
SecutityAction Class:

 
  • Assert
  • Demand
  • Deny
  • LinkDemand
  • PermitOnly
  • RequestMinimum etc…

 [assembly:UIPermission(SecurityAction.RequestMinimum,Clipboard=uipermissionclipbooard.allclipboard)]



 assembly will be loaded only if it has minimum permission to access clipboard

 
Permission set is used to combine many permission in single object and than called demand or deny on that class.
Permission set class can also be configured in configuration file.

 
The call stack is grows downward.Method lower on the call stack are called by method higher on the call stack.Each method being called has it’s own area in the call stack called staclframe, which contains parameters and local variables of the current method.

 

No comments: