Security in Application

Security is about protection. You can use the security features provided by the .NET Framework to protect your code from unauthorized users and to protect the system from unauthorized use of your code.

Overall system security policy is set by the system administrator. The administrator decides what kind of code the machine will be allowed to execute, whether or not a particular assembly is trusted, and if so, what kind of trust is extended to the assembly. The security policy set by the system administrator cannot be overridden by your code: it is the highest level of security on a given machine.

You use security to further protect your application within the bounds set by the system administrator. You can use role-based security to authorize users and code access security to protect your code from being misused by unauthorized callers. Security authorizations can be either imperative or declarative.

In imperative security, permission to execute is demanded at run time. Declarative security, on the other hand, specifies permissions required by the assembly in the assembly manifest. If the required permissions are in conflict with the security policy, the assembly will not be allowed to execute. Permission objects are the central objects in code security.


Permissions are the primary objects in security. A permission is a code object that represents a user, an identity, or a code resource. You use Permission objects for a variety of security-related functions. Permission objects are used to represent security clearances as well as to enforce security policy.

The IPermission Interface

All permissions implement the IPermission interface. Although you will very rarely, if ever, need to implement this interface, an examination of the methods described by the IPermission interface will give insight into how the objects that implement this interface work.

All security permissions in the .NET Framework must implement the IPermission interface, which provides a common level of functionality for all security objects. Permissions can use the Demand method to enforce security. The method requires that callers must have been granted the appropriate permission to access the protected code. If the appropriate permission has not been granted, a SecurityException is thrown.

The Copy method creates an identical copy of the permission, and the IsSubsetOf method determines whether the current permission is a subset of a specified permission. The Union and Intersect methods are used to create a new permission from two specified permissions of the same type. The permission returned by a Union method represents the sum of the two permissions specified, and the permission returned by the Intersect method represents only those resources that both permissions have in common. In the following sections, you will learn how to use these methods as implemented in the Permission objects provided by the .NET Framework.

Configuring Role-Based Authorization

Role-based security is security that grants or denies access to an application or resource based on the identity and role of the user. For example, suppose you have an application that is used by both managers and clerks. You might want to allow everyone to access some parts of the application, but make sensitive parts of the application, such as payroll or personal information, available to managers only. You would use role-based authorization to implement this kind of security.

The Principal

In the .NET Framework, authenticated users are represented by a Principal object. The Principal object contains information about a user's identity and role, and can be used to validate identity against a PrincipalPermission object, which is used to protect sensitive parts of an application from unauthenticated users.

Declarative Role-Based Security

Every Permission object has a corresponding attribute. These attributes can be attached to classes and members and used to control access to that class or member. Attributes play a key role in declarative security. In the declarative security model, permission attributes are attached to the members they protect to specify the level of access. Additionally, they are emitted into the type metadata so that the metadata for the assembly can be examined, and the administrator can make a decision as to whether to allow the assembly to execute or not based on that metadata.

Each permission attribute requires a SecurityAction in the constructor that indicates the action the permission attribute should take. In role-based security, this is usually a Demand action. You can set properties for permission attributes upon creation by using the := operator (Visual Basic .NET) or the = operator (Visual C#).

Configuring Code Access Security

Code access security is used to prevent your code from being misused by unauthorized callers. You can also use code access security to communicate security requirements to the system administrator, so he or she can make a decision as to whether or not to allow the assembly to execute on the system.

Like role-based security, code access security is based on permissions. In role-based security, a permission represents the identity or role of the user. In code access security, however, the permissions represent system resources and control access to those resources. A good example is the file system.

If you have an application that writes to files, you should ensure that unauthorized callers are unable to use that resource, so as to prevent maliciously inflicted damage to your file structure. You could protect any code that accesses the file system with a FileIOPermission object, which would ensure that all callers had the appropriate level of permission.

Creating Code Access Permissions

Every code access permission exposes a different set of overloaded constructors that allow you to specifically configure the resources that it protects. You can create a permission that represents access to all of the resources it protects or a subset based on the parameters supplied at instantiation.

You can create a permission that provides unrestricted access to the resource it represents by using the PermissionState.Unrestricted flag.

Imperative Code Access Security

Like role-based security, code access security can either be used imperatively or declaratively. When using imperative code access security, you enforce security at run time.

The primary method for enforcing code access security is the Demand method. Permission to access protected resources is granted by the common language runtime by checking the security policy for the assembly set by the system administrator. When the Demand method of a permission object is called, it walks the stack to verify that each and every caller higher in the call stack has been granted permission to access the resource represented by the permission.

Thus, a trusted assembly might have a method that calls another method that is protected by a code access permission. If the call to this method originates in a trusted assembly, the call will succeed, and the protected resource can be used. However, if an untrusted assembly calls the method in the trusted assembly, which then calls the protected method, the Permission object will walk the stack to verify that every caller has permission to access this resource. Because the untrusted assembly does not have the appropriate permission, the call will fail.

You can use the Assert method to declare that a method has permission to access the specified resource. This causes any Demand stack walks to cease checking for permission from callers higher in the stack. Thus, if an untrusted assembly calls a method containing an Assert call, which then attempts to call a method protected by a Demand, the Demand will be satisfied by the Assert and allow the call to proceed, even though the call originated in an untrusted assembly.

Using Assert calls can be dangerous because they can potentially allow untrusted code to access protected resources. Thus, you should be very careful when making Assert calls. You should also note that you cannot use an Assert call to bypass the system security policy. An assembly must be given the appropriate permission to make Assert calls for them to be valid.

Declarative Code Access Security

You can use declarative code access security instead of imperative code access security to configure access to system resources. As in role-based security, each code access permission has a corresponding attribute that can be attached to methods or classes to specify security actions. Additionally, you can use declarative code access security to request permissions for the entire assembly.

You can attach a code access permission attribute to a class or method in the same way in which you would specify a role-based security attribute. However, instead of specifying a role, you must specify the SecurityAction represented by the attribute.

The SecurityAction.Demand, SecurityAction.Deny, SecurityAction.Assert, and SecurityAction.PermitOnly flags correspond to the Demand, Deny, Assert, and PermitOnly methods of the relevant permission, respectively.

There are additional security actions that can be applied to classes and methods with declarative security. If you specify SecurityAction.LinkDemand, you only require the immediate caller to this class or method to have been granted the appropriate permission. Specifying SecurityAction.InheritanceDemand requires that any derived class inheriting this class or overriding this method must have the appropriate permission.

You can also use permission attributes to make security requests for the entire assembly. There are three SecurityAction flags that can be specified in an assembly-wide directive.

When SecurityAction.RequestMinimum is specified, it makes a request to the common language runtime to be granted the requested permission. If the requested permission is not granted by the security policy, the assembly will not execute. A SecurityAction.RequestOptional is similar, but the assembly will still run even if the requested permission is not granted. Specifying SecurityAction.RequestRefuse requests that the assembly be denied the specified permission.

Using Exception Handling with Imperative Security

Your applications should anticipate possible error conditions and appropriately handle any exceptions that might be thrown. Because a security failure will throw a SecurityException, any imperative security demands should be wrapped in appropriate exception handling that allows your application to degrade gracefully if security permissions are not granted.

You must decide on the appropriate course of action when a requested permission is not granted, whether that action is to allow the user to save data and then end the program or to proceed with program execution, bypassing the protected resource. Whatever course of action you decide for your application, good programming practice directs that foreseeable exceptions should never go unhandled.












No comments:

Post a Comment