.NET Security and Cryptography

The .NET Framework and Common Language Runtime (CLR) enable programmers to deal effectively with each of the important security issues described in this chapter. For example, information theft can be avoided by implementing appropriate cryptographic features into your applications. Malicious code can be stifled by defensive programming practices and by configuring appropriate user -based security and Code Access Security (CAS) features. Buffer overrun attacks become virtually impossible to implement given the secure and rigorously managed runtime environment provided by the .NET platform. Bugs resulting from buffer overruns and improper type casting are virtually eliminated by managed code and CLR runtime checks.

The following .NET platform features provide the most important aspects of protection related to security and cryptography.

  • Evidence and security policy configuration (administrative control over .NET security)

  • CAS (execution control based on evidence and security policy)

  • Role-based security (access control based on user identity and role membership)

  • Managed code runtime verification (address range checking and type checking)

  • Application domains (lightweight execution isolation)

  • Cryptography classes (access to powerful cryptographic algorithms)

How the .NET Framework Simplifies Security

One big problem with security programming using the raw Win32 API was that it was difficult to understand and difficult to use. A ridiculous number of lines of code had to be implemented in order to do the simplest operation, such as obtain a key from the operating system's current cryptographic service provider (CSP) key store. Many developers simply ignored it wherever they could get away with it. Developers who needed to apply security by directly calling the Win32 API often did the best they could with a difficult programming model.

The .NET Framework provides many simplifications by wrapping certain aspects of the underlying Win32 Security API with a powerful and simplified object-oriented interface. Many operations, such as obtaining a key from the CSP key store, now happen automatically using the .NET Security classes where appropriate. In addition, each of the classes in the .NET Security Framework that are entrusted with critical security functionality are declared as sealed classes so that they cannot be hijacked or spoofed into compromising security.

Reliability and the .NET Platform

Before you can reap the benefits of any security or cryptographic technology, you must first have the assurance of application reliability. What is the use of having a well-planned security infrastructure if the underlying application frequently falls apart? The .NET platform goes a long way to help ensure this all-important reliability requirement is satisfied. First, it is important to recognize that .NET applications are not compiled into native code. Instead, they are compiled into an intermediate form known as Microsoft Intermediate Language (MSIL, or just IL for short), much like the bytecode instruction format used on the Java [16] platform. This allows the CLR and the .NET Framework to perform many security-related services automatically, including the following:

[16] There are some truly new contributions that .NET has made to the cause of security, cryptography, and reliability. However, to be fair, it should be acknowledged that many of the most effective of these .NET security-related features were originally made available on the Java platform and in the Java Cryptography Extension (JCE) class library.

  • Bounds checking performed at runtime prevents memory corruption and stack overruns.

  • Datatype checking performed at runtime prevents improper typecasting.

  • Stack walks are used to verify permissions granted to calling code.

  • Automatic garbage collection effectively addresses memory leak problems.

  • Exception handling allows graceful response to abnormal runtime situations.

  • Role-based security is used to authenticate and limit actions of the current user.

  • Evidence-based security is used to control managed code based on permissions.

Managed Code and Type Safety

Code that can use the services of the CLR is called managed code. The CLR provides a set of services, such as type-safety checking and automatic garbage collection, that enhance application reliability and security. In order to make use of these CLR services, managed code must behave in a predictable, orderly, and consistent manner. Type safety is an important aspect of reliability and security. Type safety is made possible by the fact the CLR knows all the details about each of the managed datatypes. Using this knowledge, the CLR is able to strictly enforce rules of type safety.

For example, all datatypes, including strings and arrays, have consistent layouts and abide by strict behavioral rules. The Common Type System (CTS) defines these rules for each of the managed datatypes as well as the operations that the CLR defines for those datatypes. These restrictive rules are defined by the CTS and are implemented by MSIL. The CTS also defines each of the datatype memory layouts and the operations that are allowed in managed code. It is the CTS that limits class types to single implementation inheritance and prevents unsafe operations, such as casting an integer into a pointer and overflowing the bounds of an array. MSIL code is typically compiled [17] at runtime into the native instruction set of the local hardware after this type checking is complete.

[17] This is known as just-in-time (JIT) compilation.

To make this type-safety checking possible, .NET assemblies contain descriptive metadata that define the contained code and data. Managed data is allocated and deallocated automatically by the CLR on the heap. This automatic memory management is referred to as garbage collection . Garbage collection reduces memory leaks and related reliability problems.

Every object has a type, and therefore every reference to an object refers to a defined memory layout. Since arbitrary pointer operations are not allowed (unless the unsafe keyword is used), the only way to access an object is through its public members . Therefore, it is possible for the CLR to verify an object's safety by analyzing only the object's metadata, which is contained in the assembly. There is no need to analyze all the code that uses the object to verify that it will be used safely. Unsafe code can use pointers, which can be used to subvert the CTS and access arbitrary memory locations.

It is also possible to implement unmanaged code in the C# language using the unsafe keyword, but certain languages, such as VB.NET are capable of generating only type-safe managed code. The unsafe keyword is required for working directly with memory pointers. Unmanaged code is useful for calling into legacy DLLs, using the PInvoke facility, but unmanaged code is not verifiably type-safe by the CLR.

MSIL defines a platform-independent [18] instruction set that is used by all .NET compilers. This language implements and enforces the CTS typing rules at runtime. MSIL is then converted into platform-specific native code after the CLR type checking is complete. Type checking is performed by default, but it can be optionally skipped for code that is trusted.

[18] Platform independence for .NET CLR is possible in theory. However, it remains to be seen if the CLR is ported to as many platforms as the Java Runtime Environment.

Категории