Understanding .NET Framework Security Principles

The .NET Framework was introduced at a time when software applications were becoming increasingly more distributed, interconnected, and subsequently more vulnerable to attack. Application development was evolving from the desktop to "smart," or connected, client software and intranet- or Internet-based delivery models. This evolution brought about the need for a new paradigm in application security that would provide developers a greater level of security control to defend their applications and users against malicious attacks that could be perpetrated from external entities. Up to this point, Windows security was the norm for enforcing application access control and had traditionally been role-based. Many developers were accustomed to allowing applications to have unfettered access to local machine resources, as long as the user or user context of the running application was authorized. When .NET emerged, it was accompanied by a more integrated security model that allowed resources to be secured in a much more granular way than traditional Windows security would allow. This security model gives application developers the ability to enforce security policy within the code itself by leveraging the infrastructure that the .NET Framework provides. Let’s review some of the .NET Framework security basics.

Note

Note

It is worth noting that this chapter will not cover .NET Framework security at the level that is necessary to fully understand its features and capabilities. We will review core concepts and make recommendations, but to be truly effective with your application security policy, I recommend application developers seek a resource that provides more depth. Of course, I am a fan of the book .NET Security Programming, by Donis Marshall (Wiley, 2003).

Runtime Security Policy

The essence of Runtime Security Policy in the .NET Framework asserts that all assemblies are considered security principals and are therefore granted permissions to securable resources or particular operations. Unlike traditional Windows security, where users are the primary security principals, Runtime Security Policy in the .NET Framework challenges assemblies to authenticate themselves and be assigned execution permissions at run time. This allows application developers to govern access control within the application and subsequently provide an extra layer of security to the application users. To understand how the .NET Framework accomplishes this, let’s review the following elements of Runtime Security Policy.

  • Evidence. This is best described as the identity and origin of the executing assembly. For Runtime Security Policy to understand who the assembly is and where it is originating from, evidence must be supplied. The identity for the assembly, such as a strong name, comes from the assembly’s metadata, which gets extracted by the Common Language Runtime (CLR). Evidence of origination is submitted by the host that launches the assembly, such as the ASP.NET runtime.

  • Permissions and permission sets. These elements define specific access rights granted to a particular resource or operation. Permissions represent a grant of access rights to a singular entity, while permission sets are groupings of individual permissions that reflect a collective trust level. The .NET Framework provides several standard permissions, such as EventLogPermission, FileIOPermission, and FileDialogPermission, and several named permission sets, which include examples like FullTrust, Execution, and LocalIntranet. At run time, permission sets, not individual permissions, are what get assigned to assemblies. The .NET Framework supports custom permissions and permission sets to allow application developers to customize their needs.

  • Code groups. Simply stated, a code group is represented by an association of evidence with a permission set. Assemblies are then granted the permissions of the code group when the specific membership condition, such as having a strong name, of the code group is met. Examples of default code groups within the .NET Framework include My_Computer_Zone and Internet_Zone, to name a couple.

  • Policy levels. Policy levels reflect boundaries for the .NET Framework to calculate permission grants. There are four policy levels in .NET: Enterprise, Machine, User, and Application Domain, which are hierarchical. Additionally, each level maintains its own hierarchy of code groups and permission sets. At run time, permissions are determined based on the intersection of permission sets granted to the assembly at each policy level. Therefore, the final permission grant is represented by the sum of permissions allowed by all participating policy levels.

When granting permissions to an executing assembly, the runtime must consider the assembly’s requested permissions, the evidence provided by the host, and the security policies defined across all policy levels before rendering a decision to allow or deny access to the requested resource. 6-2 illustrates how this is accomplished through the cooperative efforts of the various elements of the Runtime Security Policy.

Overview of .NET Runtime Security Policy.

Figure 6-2. Overview of .NET Runtime Security Policy.

Now that we have reviewed the basics of Runtime Security Policy, let’s discuss how application developers can leverage the abilities of Runtime Security Policy using Code Access Security to enforce security requirements.

Code Access Security

In the .NET Framework, Code Access Security (CAS) is used to prevent code that is not trusted from accessing information or performing actions that are considered privileged. This is accomplished through collaboration with the Runtime Security Policy, whereby Runtime Security Policy sets the rules by which assemblies must abide, and CAS enforces or refines them. CAS enforces security policy through a set of checks, called demands, which ensure that any callers desiring access to a given resource actually possess permissions to do so and are not depending on the permissions of the called function. These demands initiate a stack walk that subsequently confirms the permissions granted to each method in the call stack and either authorizes access to those specific resources or throws an exception. By contrast, CAS can also be used to refine the level of permissions that an assembly or operation requires as a means to close potential security vulnerabilities. Let’s briefly review the list of functions that CAS performs.

  • Provides application code the ability to request the permissions it requires in order to run, to request permissions that would be good to have, and further specifies which permissions the code should not be allowed to have.

  • Affords administrators the ability to configure security policy by associating sets of permissions with code groups.

  • Grants permissions to each assembly that gets loaded, based on the combination of permissions that get requested by the code as well as the operations allowed by security policy.

  • Is used to define permissions and permission sets that represent access rights for various protected systems resources.

  • Gives application code the ability to demand that its callers have specific permissions.

  • Allows application code to demand that its callers possess a digital signature, thus refining access rights to only callers from a particular organization or site to call the protected code.

  • Applies restrictions on application code at run time by comparing the granted permissions of every caller on the call stack to the permissions that callers are required to have.

Applying CAS within your application can be accomplished by either using declarative or imperative syntax. Each of these approaches is acceptable, but specific implementation will depend on the security scenario you are trying to address. The following is a brief comparison of the two approaches.

  • Declarative syntax. This method of applying CAS is accomplished by decorating code with custom permission attributes. When decorating a class with declarative security attributes, the command subsequently applies to all methods of that class. By contrast, when declarative security is applied at the method level, the associative command will affect the decorated method and all of its callers.

  • Imperative syntax. This method of applying CAS is accomplished at run time. Instead of decorating classes or methods with custom attributes at design time, using the imperative syntax requires the use of security objects. Unlike the declarative syntax whose applicable granularity is at the method level, the imperative syntax allows application developers the flexibility of wrapping security code around individual lines of code.

As previously mentioned, CAS helps application developers inform the CLR about permissions that are required, not necessary, or specifically not desired. Applications cannot seek more permissions than the runtime provides based on the established policies. However, applications can use specific methods to verify permissions of a caller, refine or reduce permissions that are unnecessary, or vouch for the permissions of a caller. This is accomplished by using specific attributes or methods within your application code. Let’s briefly review the role of each type of method.

  • Demanding permissions. As we discussed at the beginning of this section, application code can demand permissions from its caller to ensure that all callers in the stack have the appropriate permission to access the operation. Once application code issues a demand, the runtime acquires the identity of all previous callers in the stack and checks the access rights of each.

  • Requesting permissions. This is a method for allowing your application code to inform the .NET runtime about the type of permissions required to execute. This is done by decorating the assembly with the appropriate permission requesting attributes. At run time, the permissions are evaluated and the appropriate security policy is applied. As previously noted, an assembly cannot request permissions beyond what the runtime assigns from the local policy. However, by applying permission request attributes to the assembly, the Runtime Security Policy will be refined further to ensure that the code is only granted the permissions that are necessary.

  • Asserting permissions. Contrary to the way demanding permissions ensures that callers higher in the stack have access to the protected resource, asserting permissions performs the opposite of demands. Asserting permissions provides application developers the ability to grant access to a protected resource even when calling code does not have permission to the resource. As you might imagine, with this power comes great responsibility. If not used correctly, permission asserts can lead to security vulnerabilities. Therefore, consider their use carefully before implementation.

Using CAS within your application designs is an important step in securing resources as well as protecting application users from potential vulnerabilities. However, all good things often come at a price. For CAS, this price is paid in application performance. This is primarily due to the stack walk performed when executing demands. When compared with the alternative of less application security, it is an acceptable design tradeoff. The important point to remember is that application performance is often easier to mitigate than a lack of security.

Applying Runtime Security Policy

Thus far, we have reviewed the basics of how Runtime Security Policy is applied by the .NET Framework through the use of evidence, permission sets, code groups, and policies. Additionally, we explored how application developers can refine or fine-tune security policies using Code Access Security. It is important for application developers and security experts within your organization to work together to establish a holistic approach to applying security across the various policy boundaries and within application code. Application security policy can be applied as a means to ensure that specific applications, Web sites, or publishers have less permission than default policy provides them. This is accomplished by using the .NET Framework Configuration Tool (Mscorcfg.msc), the Code Access Security Tool (Caspol.exe), or the Permissions View Tool (Permview.exe), which are provided with the .NET Framework software development kit (SDK), to administer security across policy levels. After reviewing the tools that are available for configuring and managing application security policy, I recommend investing some time understanding the security policy best practices outlined by Microsoft at http://msdn.microsoft.com/en-us/library/sa4se9bc.aspx.

  • The .NET Framework configuration tool. This is a Microsoft Management Console (MMC) snap-in that allows developers or system administrators to configure security policy. This tool also has the ability to manage assemblies in the global assembly cache (GAC) and configure remoting services or individual applications. From a Runtime Security Policy perspective, though, this tool provides features for increasing assembly trust, adjusting zone security, and resetting all policy levels. Mscorcfg.msc was originally released as part of the .NET redistributable package with version 1.1 of the .NET Framework. For versions 2.0 and later, Mscorcfg.msc was released with the .NET Framework SDK. To alter configuration settings on a workstation that has multiple versions of the .NET Framework, you must make the changes in the associative versions of the configuration tool.

  • Code Access Security Policy tool. This is a command-line tool that enables users and administrators to modify security policy for the machine, user, and enterprise security policy levels.

  • Permissions View tool. This is a command-line tool used to view minimal, optional, or refused permission sets requested by a particular assembly. Additionally, it is possible to use Permview.exe to view all declarative security used by an assembly.

Upon reviewing the Runtime Security Policy and Code Access Security capabilities of the .NET Framework, it should be apparent to application developers how these features could be leveraged to improve the overall security of their applications. These capabilities, in conjunction with the principles and tactics discussed earlier in this chapter, provide application developers with a framework or foundation for increasing application security and thus improving the quality of their applications. These tactics are intended to be applied during design and implementation. However, there are other practices that application development teams can apply during other stages of development as well.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.36.194