Appendix A: Understanding .NET Security
Introduction
Security in the .NET Framework and the Common Language Runtime (CLR) is much more robust than many ASP developers were accustomed to. However, these security improvements also mean new concepts for developers to understand. Sometimes these security concepts themselves can be a stumbling block to writing secure code. Once you understand the .NET Framework security concepts, you will find that that the framework actually simplifies ASP.NET security.Some of the security improvements in the .NET Framework are:
Code Access Security (CAS)
Role-based security
Security policies
It is important to understand that you can no longer ignore security as a part of your design and implementation phase. It is a priority to safeguard your systems from malicious code, and you also want to protect your code or application from being misused by less trusted code. For example, let’s say that you implement an assembly that holds functions that modify registry settings. Because these functions can be called by other unknown code, they can become tools for malicious code if you do not incorporate the .NET Framework security as part of your code.To be able to use the .NET Security to your advantage, you need to understand the concepts behind the security. We discuss those concepts in the following sections.
Permissions
In the real world, permission refers to an authority giving you, or anyone else for that matter, the formal “OK” to perform a specified task that is normally restricted to a limited group of persons. Permission has the same meaning in the .NET Security Framework: getting permission to access a protected resource or operation that is not available for unauthorized users and code. An example of a protected resource is the registry, and a protected operation is a call to a COM+ component, which is regarded as unmanaged code and therefore less secure. The .NET Framework checks the following permissions:
Code access permissions Protects the system from code that can be malicious or simply unstable.
Role-based security permissions Limits the tasks a user can perform, based on the role(s) the user plays or the user’s identity.
Custom permissions You can create your own permission in any of the other three types or any combination thereof. This demands a thorough understanding of the .NET Framework security and the working of permissions. An ill-constructed permission can result in security vulnerabilities.
You can use permissions through different methods:
Requests Code can request specific permissions from the CLR, which will authorize this request only if the assembly in which the code resides has the proper trust level. Trust level is related to the security policy that is assigned to the assembly, which is determined on the basis of evidence the assembly carries. Code can never request more permission than the security policy defines; The CLR will always deny such a request. However, the code can request less permission.
Grants The CLR can grant permissions based on the security policy and the trustworthiness of the code, and it requests code issues.
Demands The code demands that the caller has already been granted certain permissions to execute the code. You are actively responsible for this part of security.
Principal
A principal represents the caller’s identity. When code is called, either directly by a user or from other code, that code is activated within the security context of the caller. The .NET Framework references three types of principals:
Windows principal Identifies a user and the groups of which the user is a member that exist within a Windows environment. A Windows principal has the capability to impersonate another Windows user.
Generic principal Identifies a user and the user’s roles not related to a Windows user. The application is responsible for creating this type of principal. Impersonation is not a characteristic of a general principal, but because the code can modify the principal, it can take on the identity of a different user or role.
Custom principal You can construct these yourself to create a principal with additional characteristics that better suits your application. You should never expose custom principals, because doing so can create serious security vulnerabilities.
Authentication
Authentication is the verification of a user’s identity—the credentials the user hands over. Because the principal represents the caller’s identity in the .NET Framework, the code must first establish the identity of the principal. Because your code can access the information available in the principal, it can perform additional authentication tests. In fact, because you can define your own principal, you can also be in control of the authentication process. The .NET Framework supports not only the two most used authentication methods within the Windows 2000 domain—NTLM and Kerberos v5.0—but also supports other forms of authentication, such as Microsoft Passport. The .NET Framework uses role-based security to determine if the user has a role that can access the code.
Authorization
Authorization takes place after authentication, based on the established identity of the principal. Authorizing a user is the process of verifying a user’s rights to access a resource. You can refer to the user and role information in the principal object to authorize the user and allow access to system resources or to execute protected code. The principal’s permissions, based on its identity, determine if the code can access specific protected resources.
Security Policy
To be able to manage the security that the CLR enforces, an administrator can create new or modify existing security policies. Before the CLR loads an assembly, it checks the assembly’s credentials. This evidence is part of the assembly. The CLR assigns a security policy to the assembly depending on the level of trust granted. The system administrator controls security policies to fend off malicious code. The best approach in setting the security policies is to grant no permissions to an assembly for which you cannot establish an identity. The stricter you define the security policies, the more securely your CLR will operate.
Type Safety
The .NET Framework labels code type safe if it only accesses memory resources that do not belong to the memory assigned to it. Type safety verification takes place during the JIT compilation phase and prevents unsafe code from becoming active. Although you can disable type safety verification, it can lead to unpredictable results. The best example is that code can make unrestricted calls to unmanaged code, and if that code has malicious intent, the results can be severe. Therefore, the framework only allows fully trusted assemblies to bypass verification. Type safety is a form of “sandboxing.”