- Fundamental Security Benefits from the .NET Framework
- Mobile Code Solutions with the .NET Framework
- Networked Computing with the .NET Framework
- Summary
Networked Computing with the .NET Framework
Chapter 1, "Common Security Problems on the Internet," discussed several problems surrounding networked computing:
Insecure default configurations
Buffer overflows
Canonicalization errors
Information leaks
Denial-of-service vulnerabilities
As we saw in Chapter 2, the .NET Framework has many interesting features for developers, administrators, and users. Those features can help solve some of these security problems. The following sections will look at how these problems are addressed.
Insecure Default Configurations
There are numerous settings that you can tweak in the .NET Framework to affect execution behavior. Among these are some key settings that help prevent security problems from arising in .NET applications. Those settings include the following:
Default security policy (covered in detail in Chapter 8)The .NET Framework has a set of security policies that dictate what different applications are trusted to do. For instance, code downloaded from the local intranet is not allowed to directly read or write to arbitrary locations in the file system. However, it is allowed to use a File Open dialog that allows users to pick specific files an application can read.
The default security policy was carefully constructed to ensure that code originating from places other than the user's computer is constrained to a safe subset of functionality. Simply installing the .NET Framework on a machine should not open up the possibility of untrusted managed code performing arbitrary actions.
ASP.NET user account (covered in detail in Chapter 13, "Introduction to ASP.NET Security")Unlike current IIS installations, the ASP.NET worker process is not run under the SYSTEM account by default. Instead, it is run under an account with limited privileges. This is a good defense-in-depth practice that will help mitigate accidental misconfigurations of servers or bugs that may be found in the ASP.NET code in the future.
The ASP.NET process can be configured to use the SYSTEM account if necessary. However, basic ASP.NET pages shouldn't need special privileges, so an account with limited privileges is fine.
Buffer Overflows
Fortunately, buffer overflows are much less of a problem when dealing with a managed application. String and array copying have tight bounds checking in the .NET Framework class libraries. This alone should help decrease the number of serious security holes in applications.
Note that managed applications do not completely eliminate buffer overflows. This is primarily because all managed applications run unmanaged code at some level. The .NET Framework core unmanaged code has been closely inspected for buffer overflows, so few should remain there. However, if a managed application uses the interoperability functionality to access classic COM objects or platform APIs, the unmanaged code will execute. Thus, if a managed application uses unmanaged components or API calls, buffer overflows are still possible. In these cases, careful code reviews are necessary to mitigate the risk of buffer overflows.
Using "unsafe" C# functionality or manually constructed IL can lead to unverifiable managed applications. Unverifiable applications can also have buffer overflow problems because their behavior has considerably fewer execution guarantees. However, nearly all managed code you write should be verifiable, so managed buffer overflows should be very rare.
Canonicalization Errors
Canonicalization errors are probably as easy to create in managed code as they are in unmanaged code. This is because they cannot be broadly fixed in applications by changing underlying .NET Framework behavior. They are bugs specific to each application. For instance, if some application is supposed to parse a string for specific commands to execute, the key to correctness is proper parsing logic. Bad logic will cause problems in managed and unmanaged applications.
There are some tools from the .NET Framework class library that can help prevent canonicalization errors. The System.Text.RegularExpressions namespace has classes to deal with regular expressions, which are very helpful when dealing with arbitrary strings. The System.Uri class provides a mechanism to canonicalize URIs. The System.IO.Path class can provide an absolute file path for any given relative file path.
Information Leaks
This is another area where the .NET Framework cannot solve an entire class of problems. Software deals with information from different sources, and determining what information can be safely shared is a complicated process. Some data, such as passwords and credit card numbers, is usually understood to be sensitive information that should not be freely handed out. Other information, such as machine names, usernames, and network topology data, isn't as widely known to be data that should be protected.
Some managed code has explicit checks to ensure that information isn't leaked. For instance, file paths (which can include usernames), private class information in assemblies, and network topology information from DNS queries are all protected by the .NET Framework when directly accessed using the .NET Framework class library. However, this information can all be accidentally handed out by a poorly written .NET component. Thus, it is really up to application writers to ensure that their applications don't cause these sorts of problems.
Denial-of-Service Vulnerabilities
Version 1 of the .NET Framework doesn't focus on fixing denial-of-service issues. Thus, it should be expected that untrusted managed code can cause .NET Framework hosts to stop responding. If you intend to use the .NET Framework in semitrusted environments such as Web-hosted applications, you will have to take care to accommodate faulty or malicious code. For example, a managed code host might want to only allow user applications to execute for a short amount of time before they are automatically killed.
Note that denial-of-service attacks should not be able to cause arbitrary code execution or information leaks. Instead, the effects should be temporary until the offending code is stopped or the host is restarted.