BUY THIS BOOK
Add to Cart

PDF $35.99

Safari Books Online

What is this?

Looking to Reprint or License this content?


Programming .NET Security
Programming .NET Security

By Adam Freeman, Allen Jones
Book Price: $44.95 USD
£31.95 GBP
PDF Price: $35.99

Cover | Table of Contents | Colophon


Table of Contents

Chapter 1: Security Fundamentals
This chapter introduces the fundamental software security concepts that you need to understand before continuing to later chapters. We explain why there is a need for security, and the roles that are important to the development and operation of software security policies. We also discuss the goals of software security and introduce some important concepts that you should understand as you develop your own security programming skills.
Only a few years ago, software applications tended to be isolated. Users of these applications were required to present themselves in a known location (for example, a bank branch or office block) that was protected by physical barriers to access such as locks, surveillance cameras, and security guards. Attacks against such software systems were fewer than are experienced today, in part, because gaining access to such a location presented a barrier that many found insurmountable.
The increased connectivity and prevalence of networked applications has removed the insurmountable barrier presented by physical security, and it is not only the networked applications themselves at risk. Increasingly, software systems control access to valuable physical resources (for example, banking software can be used to credit or debit a customer account). Subverting or compromising the software system may be the simplest way to gain access to the physical resource; for example, it may be easier to break into the banking application and create fictitious transactions than it is to crack open the bank vault.
Today, a talented 15-year-old Italian schoolboy, who would be unable to get past a company security guard, might, for personal amusement, be able to convince a networked application that he is a 37-year-old trusted employee from Alabama. More serious, however, is the increase in software hacking for criminal reasons—either to steal intellectual property or, more commonly, to steal information that can be sold to other criminals, such as lists of credit card numbers.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
The Need for Security
Only a few years ago, software applications tended to be isolated. Users of these applications were required to present themselves in a known location (for example, a bank branch or office block) that was protected by physical barriers to access such as locks, surveillance cameras, and security guards. Attacks against such software systems were fewer than are experienced today, in part, because gaining access to such a location presented a barrier that many found insurmountable.
The increased connectivity and prevalence of networked applications has removed the insurmountable barrier presented by physical security, and it is not only the networked applications themselves at risk. Increasingly, software systems control access to valuable physical resources (for example, banking software can be used to credit or debit a customer account). Subverting or compromising the software system may be the simplest way to gain access to the physical resource; for example, it may be easier to break into the banking application and create fictitious transactions than it is to crack open the bank vault.
Today, a talented 15-year-old Italian schoolboy, who would be unable to get past a company security guard, might, for personal amusement, be able to convince a networked application that he is a 37-year-old trusted employee from Alabama. More serious, however, is the increase in software hacking for criminal reasons—either to steal intellectual property or, more commonly, to steal information that can be sold to other criminals, such as lists of credit card numbers.
In short, the world has become more hostile towards software. In light of recent changes to social and political attitudes to security, it should be no surprise that the public has an increased expectation that software will be secure. The kinds of security that we discuss in this book can provide some protection against the increased frequency and sophistication of attempts to subvert applications. However, security has also become a tool to promote the sale of software, and claims of "unbreakable" security are now commonplace. The effective use of software security has fallen behind the ideal that is portrayed by marketing departments. Another purpose of this book is to close the gap between the perception and the reality, and to demonstrate how you can increase the security of your applications through the careful application of tried-and-tested technologies.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Roles in Security
In a normal software development project, there are many people who influence software security. People often look at software security from different perspectives and hope to gain different results from its implementation; these are often at odds with the goals of others. In this section, we describe the most common roles, and explain the motivations and goals of those who hold them. The content of this book is aimed at the technical reader, but it is important that you appreciate the complete set of influences that shape the need for and implementation of software security. See Chapter 4 for a more detailed examination of some of these roles and the way they influence the life cycle of an application.
The business sponsor is responsible for commissioning a software development project, and usually owns the problem that the application is intended to solve. The role of the business sponsor, and his expectations of software security, varies depending on the nature of the business and the purpose of the software.
The business sponsor typically lacks technical expertise, but controls the development budget and may support the implementation of software security for the following reasons:
  • Security is a known requirement of the systems users.
  • Legislation dictates that the software must implement certain security measures.
  • Security features are necessary to compete with other products and look good on marketing material.
Lacking formal requirements, the business sponsor will often have opinions to offer on the importance and implementation of software security. These opinions may or may not be in line with the real requirements of the project.
Business sponsors are often the biggest source of tension on a project when it comes to the correct application of security. As you will see throughout this book, software security can be applied only after a careful assessment of the application requirements; however, the business sponsor often wants to bring the application into production as quickly as possible, and this creates a tension between the careful application of a planned security policy and the business requirement that the application ship quickly.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Understanding Software Security
There are two kinds of assets that software security sets out to protect; restricted resources and secrets. In this section, we provide an overview of these important categories, which we build on throughout the rest of the book.
A restricted resource is any object, feature, or function of your application (or of any software or hardware that your application depends on) that you do not wish to be used or accessed by unauthorized people. This is a very broad definition, but casting our net this wide allows us to demonstrate the common solution to a wide range of closely related issues; the following list describes some restricted resources that you may encounter:
Disk files
The most commonly encountered restricted resource is the disk file. For example, by default, the Windows operating system allows users to access their own files, but not the files of other users or disk files used by the operating system itself. Users are restricted from accessing files that they have not created.
Software functions
One of the most familiar restricted resources for you is the software function that should not be available to all users of the application or service. For example, the accounts clerk in a bank should not be able to authorize mortgage loans; such activities are restricted to qualified loan officers.
Hardware resources
Software security is often used to restrict access to important hardware resources, such as a high-quality color printer. Ordinary users are restricted to printing their documents in monochrome, while the sales staff prints customer presentations in color.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
End-to-End Security
The final concept we introduce in this chapter is end-to-end security , which is the result of considering the wider aspects of security, beyond the resources and secrets protected by your application. Although this book is focused on implementing software security, it is important that you take a higher-level view, taking into account the real world and its complexity. The following sections highlight other issues that you should consider.
One of the most important things to remember about security is that not everyone shares your motivations and aspirations, and not everyone thinks the way that you think. The most carefully defined software trust system may not reflect the actual trust that has been granted to users of an application.
As a simple example, when we outlined the important roles that play in security, we differentiated between the legitimate users of an application and the hackers who want to subvert it. The reality is less clear-cut; most fraud is perpetrated by employees otherwise trusted by their company; when you grant trust to a user, you may be providing that individual tools that will be used to defraud, and otherwise rob, your company.
Differences in motivation are especially relevant when considering coercion; although you may feel that the security and profitability of your application is paramount, others may not. In some countries, it is common to rob a bank by kidnapping the branch manager's children, coercing the manager to unlock the bank and provide access to the vaults in order to secure the freedom of his offspring. The robbers have secured access to the protected resources with the explicit cooperation of a trusted employee. When thinking about security, you must give consideration to motivation, both of the potential users and the potential attackers.
A side-channel attack employs methods that have little to do with the software security measures that protect an application. For example, looking over a person's shoulder while he types his password circumvents any policy that may be put in place to control identity authentication; the attacker has side-stepped the security measures and can now access the system.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 2: Assemblies
This chapter provides an overview of the .NET assembly, which is a key component in .NET security. We describe the structure and contents of an assembly, demonstrate how to create the different types of assembly, and discuss how you can protect your assemblies from tampering and reverse engineering. The information in this chapter provides a foundation essential for understanding the more advanced topics presented in later chapters, especially those related to Code Access Security.
An assembly contains one or more .NET data types compiled into the Microsoft Intermediate Language (MSIL); in other words, an assembly contains the code that the common language runtime executes. The .NET Framework uses the assembly as the basic unit of deployment and versioning and, most importantly for our purposes, as the basic security boundary. In the following chapters, we will demonstrate how the .NET Framework uses assemblies to enforce security policy; in this section, however, we provide a brief overview of assemblies as a foundation for more advanced topics.
Each assembly consists of the following:
Assembly manifest
The assembly manifest contains metadata elements that describe the assembly, summarized as follows:
Assembly name
A text string specifying the assembly's name
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Assemblies Explained
An assembly contains one or more .NET data types compiled into the Microsoft Intermediate Language (MSIL); in other words, an assembly contains the code that the common language runtime executes. The .NET Framework uses the assembly as the basic unit of deployment and versioning and, most importantly for our purposes, as the basic security boundary. In the following chapters, we will demonstrate how the .NET Framework uses assemblies to enforce security policy; in this section, however, we provide a brief overview of assemblies as a foundation for more advanced topics.
Each assembly consists of the following:
Assembly manifest
The assembly manifest contains metadata elements that describe the assembly, summarized as follows:
Assembly name
A text string specifying the assembly's name
Assembly version
A string in the form a.b.c.d, where a and b are major and minor version numbers, and c and d are revision and build numbers
Assembly culture
Information on the culture or language that the assembly supports, for example, "en-US" for U.S. English or "fr-CA" for Canadian French
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Creating Assemblies
To transform source code files into assemblies, you must use a language-specific .NET compiler. For C# source code files, we use the C# compiler (csc.exe) and we use the Visual Basic .NET compiler (vbc.exe) for Visual Basic .NET source files. In this section, we will demonstrate how to create single- and multifile assemblies; we do not go into detail about how to use the .NET compilers. We begin by defining two simple types, the first of which is as follows:
# C#

public class SumNumbers {
    private int o_total;

    /// <summary>
    /// Default constructor - initializes the total to zero
    /// </summary>
        public SumNumbers(  ) {
                // initialize the total
        o_total = 0;
        }

    /// <summary>
    /// Add a number to the total
    /// </summary>
    /// <param name="p_number">The number to add</param>
    public void AddNumber(int p_number) {
        o_total += p_number;
    }

    /// <summary>
    /// Get the total
    /// </summary>
    /// <returns>The total of all values presented to AddNumber</returns>
    public int GetTotal(  ) {
        return o_total;
    }
}

# Visual Basic .NET

Public Class SumNumbers
    Private o_total As Integer

    Public Sub New(  )
        ' initialize the total
        o_total = 0
    End Sub

    Public Sub AddNumber(ByVal p_number As Integer)
        o_total += p_number
    End Sub

    Public Function GetTotal(  ) As Integer
        Return o_total
    End Function
End Class
The SumNumbers class maintains a running total of integer values using the AddNumber method; the total value is obtained using the GetTotal method. The second type, SumArray, defines the static member SumArrayOfIntegers, which accepts an array of integers to be added together; this class is a consumer of SumNumbers.
# C#

public class SumArray {

    /// <summary>
    /// Static method that sums together the values in 
    /// an array of integers
    /// </summary>
    /// <param name="p_arr"></param>
    /// <returns></returns>
    public static int SumArrayOfIntegers(int[] p_arr) {
        // create a new instance of SumNumbers
        SumNumbers x_sum = new SumNumbers(  );
        // add each value in the array to the sum
        foreach (int x_int in p_arr) {
            x_sum.AddNumber(x_int);
        }
        // return the total from the sum
        return x_sum.GetTotal(  );
    }
}

# Visual Basic .NET
Public Class SumArray

    Public Shared Function SumArrayOfIntegers(ByVal p_arr(  ) As Integer) _
    As Integer
        ' create a new instance of the SumNumbers class
        Dim x_sum As SumNumbers = New SumNumbers
        ' add each value in the array to the sum
        Dim x_int As Integer
        For Each x_int In p_arr
            x_sum.AddNumber(x_int)
        Next
        ' return the total from the sum
        Return x_sum.GetTotal(  )
    End Function
End Class
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Shared Assemblies
Assemblies can be private or shared, as illustrated by Figure 2-3. Each application that uses a private assembly has its own copy, which is stored alongside the other application components. If there are two applications installed on the same computer, and each application relies on the same private assembly, then there will be two copies of the assembly files installed. Each time you install a new application that relies on the private assembly, you create new instances of the assembly files on disk. Each assembly is independent of the others, and each application is completely self-contained.
Figure 2-3: Private and shared assemblies
By contrast, several applications can use a single instance of a shared assembly. The assembly is placed in a common location (a shared directory or network server), and every application that requires the assembly uses the same assembly disk files. More than one copy of a shared assembly can be installed, and groups of applications can rely on different instances, as illustrated by Figure 2-4.
Figure 2-4: Groups of applications relying on multiple identical private assemblies
The .NET Framework also provides the Global Assembly Cache (GAC), which is a central repository for shared assemblies. All applications that rely on a shared assembly stored in the GAC use the same disk files, as illustrated by Figure 2-5; such applications do not need to be configured to find shared assemblies in specific locations; the GAC is always available to all applications. See Section 2.5.1 for further details.
Figure 2-5: The GAC hosts shared assemblies
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Strong Names
Shared assemblies must have a strong name. A strong name consists of the assembly's name, version and culture metadata, plus a cryptographic public key and a digital signature. Because it is sufficiently unlikely that two different assemblies will have the same strong name, Microsoft considers a strong name to be a unique identifier of an assembly. Two properties of digital signatures support this position:
  1. Digital signatures are associated with a hash code generated from the contents of the assembly; this hash code acts as a "fingerprint" for the assembly contents, and it is very difficult to find two assemblies with the same fingerprint.
  2. Cryptographic key pairs, used to create the digital signature, are created randomly.
The randomness of key pairs, and the uniqueness of the fingerprint provided by the digital hash code and signature, means that a strong name, for all practical purposes, provides a unique identification for an assembly. See Chapter 13 for details of digital hash codes and Chapter 16 for details of digital signatures.
The chapters in the Cryptography section of this book provide information about assessing the cryptographic meaning of words and phrases such as "unique" and "very difficult."
The uniqueness of a strong name allows the .NET Framework to verify the contents of an assembly to protect against tampering; the hash code generated from the assembly contents means that changing even a single MSIL statement will invalidate the digital signature, leading the .NET Framework to reject the assembly. This protection against tampering is a fundamental security feature of strongly named assemblies and is a key function in the life cycle of a .NET application, which we discuss in Chapter 4. Strong names are a key feature of code access security, which we discuss in Chapter 6 through Chapter 9.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Publisher Certificates
Strong names provide unique identities for assemblies and protect against tampering, but they do not contain any information about the identity of the assembly publisher. The .NET Framework supports the Signcode scheme, which requires a publisher to prove its identity to a trusted third-party authority and obtain a software publisher's certificate (SPC). Strong names and Signcode are complimentary technologies, and both can be applied to the same assembly. When you use Signcode, a digital signature is created using the private key component of the certificate and is embedded into the assembly along with the public components of the SPC. The digital signature provides the link between your SPC and the assembly you signed; other parties cannot sign assemblies with your SPC unless they know the value of the secret key, which is not included in the assembly. See Chapter 15 for more information about public and private keys.
You can use the Certificate Creation tool (makecert.exe ) to create an X509 certificate for testing purposes and then convert it to an SPC; genuine certificates are obtained from companies such as Verisign. The following command creates a new X509 certificate; the Certificate Creation tool supports a number of options to configure the test certificate, but we will accept the defaults. The test certificate is stored in a file named TestCert.cer:
makecert -sv MyPrivateKey.pvk TestCert.cer
The -sv option stores the private key component of the certificate in a file named MyPrivateKey.pvk; you will need to use this key later. You will be prompted to enter a password to protect the private key file, as shown in Figure 2-6.
Figure 2-6: Protecting the private key component of the X509 certificate with a password
Convert the X509 certificate into an SPC with the Software Publisher Certificate Test tool (
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Decompiling Explained
When you compile source code into an assembly, the compiler interprets your C# or Visual Basic .NET statements, and creates a series of MSIL statements that will be executed by the .NET Framework. A decompiler is an application that analyses the MSIL statements in order to recreate the original Visual Basic .NET or C# statements written by the programmer.
Unfortunately, the .NET compilers contain human-readable information from our source code in the MSIL, including the names of types, methods, and fields. A decompiler can use this information to create source code that is very similar to the original. Some information, such as comments and blocks of code excluded by conditional compiler statements, are not included in assemblies by the compiler and cannot be restored by a decompiler.
The nature of MSIL makes it easier to decompile .NET assemblies than native Windows applications, which are compiled into instructions that are targeted at a specific CPU, such as an Intel Pentium. Lower-level instructions are more difficult to reconstruct into code statements than the relatively abstract MSIL statements. The proliferation and use of decompilers is more widespread than you might think. There are three main reasons why an assembly is decompiled:
Interest
The most benign reason for decompiling an assembly is simply to gain an understanding of how an application or library is written; the person who decompiles the assembly has no malicious intent, and simply seeks to improve her knowledge of .NET programming.
Intellectual property theft
Your assemblies can be decompiled to reveal your business secrets, which can be used commercially by your competitors. In this context, business secrets may be proprietary algorithms, or the inner workings of your complete application.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 3: Application Domains
Application domains play a critical role in the implementation of the Microsoft .NET Framework's security model. Although you will rarely need to work directly with application domains when writing simple applications, they become an essential program element once you start writing more complex systems—in particular, systems that utilize and manipulate the code-access security (CAS) mechanism of the Microsoft .NET Common Language Runtime (CLR).
Only highly trusted code can manipulate application domains—we discuss the specific permissions required to carry out various operations in Chapter 5, Chapter 6, and Chapter 7. For now, it is enough to know that applications running from the hard drive of your machine can utilize all of the techniques we describe here as long as you have not modified .NET's default security policy.
To ensure application and operating system security and stability, it is necessary to isolate concurrently executing applications from each other. Application isolation ensures that one application cannot purposefully or inadvertently modify the memory, or access the resources owned by another. Traditionally, operating systems isolate applications by running each application in its own process, and providing each process with its own virtual memory space and resource handles. Memory references are associated with a single process, and therefore code cannot obtain a reference that affects the memory of another process. Code cannot access objects in other processes directly and must use some intermediate communications mechanism, such as a remote procedure call or a proxy in order to invoke methods.
Application isolation in the .NET Framework is very different from traditional application environments. Before the CLR loads an assembly, it verifies that the assembly contains only type-safe code. Type safety guarantees that the code does not perform illegal operations, access memory directly, or try to access type members incorrectly. If an assembly fails the verification process, the CLR will refuse to load it and will throw an exception. We discuss the verification of assemblies further in Chapter 4.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Application Domains Explained
To ensure application and operating system security and stability, it is necessary to isolate concurrently executing applications from each other. Application isolation ensures that one application cannot purposefully or inadvertently modify the memory, or access the resources owned by another. Traditionally, operating systems isolate applications by running each application in its own process, and providing each process with its own virtual memory space and resource handles. Memory references are associated with a single process, and therefore code cannot obtain a reference that affects the memory of another process. Code cannot access objects in other processes directly and must use some intermediate communications mechanism, such as a remote procedure call or a proxy in order to invoke methods.
Application isolation in the .NET Framework is very different from traditional application environments. Before the CLR loads an assembly, it verifies that the assembly contains only type-safe code. Type safety guarantees that the code does not perform illegal operations, access memory directly, or try to access type members incorrectly. If an assembly fails the verification process, the CLR will refuse to load it and will throw an exception. We discuss the verification of assemblies further in Chapter 4.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 4: The Lifetime of a Secure Application
This chapter looks at the way in which software security is integrated into the application lifetime and provides practical advice that will help you understand the content contained in later chapters.
We define the term secure application to mean an application designed with security in mind. We firmly believe that truly effective software security is achieved only when it is completely integrated into the application development process and is understood to be every bit as important as stability, performance, and feature completeness.
We recommend that you read this chapter twice. Read it now to help build a context for the technical content of the following chapters. When you have finished reading this book and have a better grasp of .NET security, read this chapter again, and consider how you can improve your development process to best implement the advice and recommendations we make.
With few exceptions, a design is produced for an application before development begins; for smaller projects, the programmers may produce the design, which may be closely related to the implementation and contain low-level technical details. Larger projects usually engage an application architect to produce a more abstract design, leaving development of it's components to individual development teams.
Security is an important part of the design process and cannot be left until the implementation phase. A fully integrated security policy will provide the greatest protection against your application being subverted and simplify the process of integrating security functionality into your code. You cannot retrofit a comprehensive security model into a design.
As the application designer, you need to have an understanding of the security capabilities provided by the platform that the application uses, in the same way that you must understand the features and functions of other components, such as databases and operating systems. This knowledge is important even if you will not be involved in the implementation of the application. Where possible we have written each chapter so that an explanation of the security features offered by .NET is separate from the details of how to apply the functionality during coding; we recommend that architects working at even the most abstract levels should read the latter material.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Designing a Secure .NET Application
With few exceptions, a design is produced for an application before development begins; for smaller projects, the programmers may produce the design, which may be closely related to the implementation and contain low-level technical details. Larger projects usually engage an application architect to produce a more abstract design, leaving development of it's components to individual development teams.
Security is an important part of the design process and cannot be left until the implementation phase. A fully integrated security policy will provide the greatest protection against your application being subverted and simplify the process of integrating security functionality into your code. You cannot retrofit a comprehensive security model into a design.
As the application designer, you need to have an understanding of the security capabilities provided by the platform that the application uses, in the same way that you must understand the features and functions of other components, such as databases and operating systems. This knowledge is important even if you will not be involved in the implementation of the application. Where possible we have written each chapter so that an explanation of the security features offered by .NET is separate from the details of how to apply the functionality during coding; we recommend that architects working at even the most abstract levels should read the latter material.
The first step towards applying security to an application design is to identify the restricted resources and secrets, two concepts that we introduced in Chapter 1. Recall that a restricted resource is functionality to which you wish to control access to, and a secret is some piece of data that you wish to hide from third parties.
Restricted resources tend to fall into three categories:
Functional resources
Functional resources are the features that your application provides, for example, the ability to approve a loan within a banking application. These resources are easy to identify and are defined with the functional specification for the application.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Developing a Secure .NET Application
The developer takes the application design from the architect and develops the classes that form the application implementation. The developer must have a good working knowledge of software security, and especially the security features provided by the development platform. This knowledge is required so that the developer can correctly program the security policy as part of the implementation process.
The developer takes a much more concrete approach than the abstract approach taken during the design, and takes the broad policy laid out in the application design and transforms it into a robust and accurate implementation.
We do not suggest that the developer should follow the application design to the exclusion of everything else. As the developer, you have an obligation to assess the practicality and suitability of the application design, and the security policy the design defines. Question the design appropriately and bear in mind that your in-depth knowledge of programming security should be used to collaborate on improving a faulty design, rather than as a weapon in a political or cultural war. Nonetheless, respect the purpose of the application design, and do not deviate from it unless you have the architect's permission—needlessly deviating from the design will lead to implementation defects, which can present unforeseen opportunities to attack and subvert your application.
The developer is often responsible for making implementation decisions, such as the strength of cryptography used to protect secrets or the way security roles are employed. There is often a temptation to adopt new and exciting technologies, which is a dangerous approach when applied to application security. Security is best established by using tried-and-tested techniques, and by using algorithms and implementations that have been subjected to extensive testing.
As you will see in later chapters, .NET security is implemented by the developer but is configured by the system administrator. You should implement your security policy to simplify the configuration wherever possible, and to use default settings that offer a reasonable level of security without any configuration at all. You cannot expect a system administrator to have the in-depth knowledge required to develop the application or the time to invest in learning the intricacies of your application. Document the default settings you have used, and explain their significance. We offer the following advice to assist you in developing applications securely:
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Security Testing a .NET Application
As we stated in Chapter 1, security testing is unlike ordinary application testing—the security tester looks for ways to subvert the security of an application prior to its deployment. Effective security testing can significantly reduce the number of security defects in an application and can highlight flaws in the application design. We offer the following advice to assist you in security testing applications:
  • Play the part of the employee. Do not limit your simulated attacks to those you expect a hacker to make—be sure to determine if it is possible for a disgruntled employee to subvert the application security. Employees are usually assigned more trust in an application security model, which can sometimes provide easier routes of attack.
  • Test beyond the application itself. Your testing should include attacks on the system on which the application depends, including database, directory, and email servers. In the case of .NET, you should also see if you can subvert your application via an attack on the runtime components. Poor configuration or a poor understanding of security functionality can often provide an avenue for an attack that can subvert the application indirectly.
  • Test beyond the application design. Do not fall into the trap of simply testing to ensure that the application design has been correctly implemented; this is functional testing, and it does not offer many insights into security failures.
  • Monitor trends in general attack strategies. Expand your range of simulated attacks by monitoring the way real attacks are performed. Your customers may furnish you with descriptions of attacks they have seen, and you can learn from the way other applications and services are attacked.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Deploying a .NET Application
The system administrator is responsible for installing and configuring the application. This task includes assigning user accounts to the roles defined by .NET role-based security (see Chapter 10) and assigning appropriate levels of trust to the assemblies that make up the application. Equally important is the configuration of the services required by the application, such as database and directory servers.
If you are the system administrator, you have an obligation to gain an understanding of how the application should be configured, and to spend the time to determine how the security configuration is best tailored to your enterprise. You have a reasonable expectation that the software publisher will provide you with a robust and functional application, and the software publisher has a reasonable expectation that you will install and configure its application by following its instructions and by applying your knowledge of the company.
Nonetheless, you should consider carefully the levels of trust that you assign to a publisher's assemblies, and ensure that you are not granting an application more permissions than it requires to perform correctly. You should also ensure that you are not compromising the security of your corporate network by configuring the application and the services that it depends on.
Your final obligation is to monitor the application in order to watch for security defects or breaches and to report these problems to the software publisher. See Section 4.6 for an explanation of how the management of security continues for as long as the application is in use.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Executing a .NET Application
Once a system administrator has installed and configured the application, it can be executed using the Common Language Runtime (CLR). The CLR is a complex piece of software, and a detailed discussion of how the CLR works is outside the scope of this book. In this section, we discuss the two facets of CLR operation that relate specifically to security.
Verification is the first aspect of the CLR we are interested in. Before executing a managed application, the CLR completes a verification process that is the first step toward enforcing .NET security. If the application is made up of strong-named assemblies (see Chapter 2 for details), then the contents of the assemblies are checked and compared with the value of the digital signature; the CLR will not execute code from any assembly that has been tampered with. If the contents of the assembly are unchanged, the CLR verifies that the code contained within the assemblies is type-safe, meaning that the code does not perform illegal operations, access memory directly, or try to access type members incorrectly.
If the code contained in the assemblies is type-safe, and the contents of the assembly have not been tampered with, then the CLR examines the evidence of each assembly, and grants permissions to the code within that assembly based on the .NET security policy configuration. We discuss evidence in Chapter 6, permissions in Chapter 7, and security policies in Chapter 8.
The important fact, and one you must understand, is that the security implementation (performed by the developer) and the configuration (performed by the system administrator) are combined by the CLR when the application is started to determine how the application is allowed to execute. .NET security is not simply proscribed by the software publisher; it is something that requires the cooperation and understanding of the customer.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Monitoring a .NET Application
It is extremely difficult to develop and deploy software that is reasonably secure, and impossible to develop and deploy software that is invulnerable to attack. Reconcile yourself to the fact that you application may be subverted, and plan accordingly.
Do not stop thinking about the security of your application when you have deployed the final product, or even when the system administrator has completed the configurations and users are making use of the functionality. The impact of security lasts as long as the life of the application itself; you should be prepared to monitor for security breaches, and have a plan in place to deal with them.
An effective weapon against hacking is education; you should ensure that your customers understand how you have applied security within your application, assist them in understanding how to recognize an in-progress attack, and how to tell when a hacker has bypassed or subverted your application security. You should aim to build a relationship with your clients that makes it possible for them to report security problems to you, and endeavor to respond to such reports in a responsible and sensible manner. We believe that as a publisher of software, your responsibilities include:
Analyzing security reports
If you are successful in establishing a way in which customers can report security attacks and defects, you have a responsibility to use this information to assess the impact of potential problems and act to reduce the risk to your customers and users.
Assisting your customers in developing a failure strategy
You should portray the security software techniques you apply to your applications in an accurate and honest manner, and not make unreasonable or unlikely claims. You should educate your customer, ensuring that they understand that no security precautions are impervious to concerted attack, and help them to develop a plan of action to execute in the event of a successful subversion of your security measures. Such a plan should contain a reasonable approach to assessing the impact of the attack and steps to take to restore the application to service.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Chapter 5: Introduction to Runtime Security
In this chapter, we introduce the security features provided by the .NET runtime that most directly affect the code you develop and run. At a high level, we explain the purpose and function of these security features, how they interact with each other, and their relationship with the security provided by the underlying operating system. In the next six chapters, we explore these features in detail, demonstrate how to use them in your own programs, and show you how to extend and customize them.
The .NET Framework is a flexible general-purpose computing platform designed to address the needs of commercial organizations and individuals alike, and supports many different application models. However, .NET places an emphasis on supporting the trend towards highly distributed systems, component-based applications, and web-based server solutions, including XML web services.
The .NET Framework is designed to run on multiple operating system platforms. Although Windows is currently the platform of choice for .NET deployment, there are implementations available for FreeBSD, Linux, and Mac OS X that are compliant with ECMA Standard 335 (which defines the core functionality of the .NET Framework). It is likely that in the future, .NET applications compliant with ECMA Standard 335 will run and integrate seamlessly across a variety of other operating systems.
The .NET Framework's strong support for distributed application models and its cross-platform capabilities means that software is more mobile, accessible, and integrated than before; although this provides functionality and productivity benefits, it also means that software consumers, producers, and service providers need to place a greater emphasis on software and system security. The increase in accessible web-based server solutions and mobile components also produces an increase in the number of people who try to hack those systems or who distribute malicious code in the form of viruses, worms, and Trojan horses for the purpose of gathering information or causing damage.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Runtime Security Explained
The .NET Framework is a flexible general-purpose computing platform designed to address the needs of commercial organizations and individuals alike, and supports many different application models. However, .NET places an emphasis on supporting the trend towards highly distributed systems, component-based applications, and web-based server solutions, including XML web services.
The .NET Framework is designed to run on multiple operating system platforms. Although Windows is currently the platform of choice for .NET deployment, there are implementations available for FreeBSD, Linux, and Mac OS X that are compliant with ECMA Standard 335 (which defines the core functionality of the .NET Framework). It is likely that in the future, .NET applications compliant with ECMA Standard 335 will run and integrate seamlessly across a variety of other operating systems.
The .NET Framework's strong support for distributed application models and its cross-platform capabilities means that software is more mobile, accessible, and integrated than before; although this provides functionality and productivity benefits, it also means that software consumers, producers, and service providers need to place a greater emphasis on software and system security. The increase in accessible web-based server solutions and mobile components also produces an increase in the number of people who try to hack those systems or who distribute malicious code in the form of viruses, worms, and Trojan horses for the purpose of gathering information or causing damage.
Cross-platform solutions cannot always rely on the underlying operating system to provide the same security services on all platforms. The .NET runtime implements the following three features that provide platform-independent security services to improve the security of both client- and server-side software solutions:
  • Role-based security
  • Code-access security
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Introducing Role-Based Security
The .NET Framework provides a generic role-based security mechanism to represent the identity and roles of the user on whose behalf code is running. As illustrated in Figure 5-1, you can use .NET's role-based security mechanism to integrate with an existing user account system, such as that provided by Windows or Microsoft's Passport .NET authentication mechanism. However, it is just as easy to integrate with other custom user account mechanisms.
Figure 5-1: Role-based security
Regardless of the underlying source of user information, .NET's role-based security interfaces provide a standard mechanism through which you can make runtime security decisions based on the identity and roles of a user. For example, you can make decisions, such as:
  • Ensure that only users who are members of the "Administrators" or "Managers" roles can execute a protected class member
  • Ensure that only the user "Peter" can load a class that inherits from a protected class
.NET's abstraction of the role-based security interfaces from the underlying authentication and authorization mechanisms make it relatively easy to change from one mechanism to another should the need arise. We provide a detailed coverage of .NET's role-based security mechanisms in Chapter 10.
Additional content appearing in this section has been removed.
Purchase this book now or read it online at Safari to get the whole thing!
Introducing Code-Access Security
An important goal of the .NET Framework is to facilitate the development of highly distributed, component-based systems. With the .NET Framework, you can easily create applications that utilize code from different publishers, dynamically loading assemblies from different locations as required. Internet Explorer is an early example of this flexible architecture: downloading and executing .NET controls on demand, and giving the user a rich interface to the Web. Over the coming years, you can expect to see many more .NET applications componentized and delivered "on demand."
Traditionally, code executes using the identity, roles, and permissions of the user that runs it. As we discussed in the previous section, role-based security is important for ensuring system security. However, in a connected world where distributed systems and highly mobile code are the order of the day, it is insufficient to base system security decisions solely on the permission granted to the user running an application. Faulty code can damage files to which the user has access, or, worse, malicious code can take advantage of the user's authority to perform all kinds of mischief. A highly trusted user (with extensive system permissions) cannot freely download and run an application from an untrusted source for fear of what the code may do to his system and other systems on his network.
Many companies tackle the problem of code security by "locking down" their users' desktops, restricting the applications that people can install and run. This heavy-handed approach requires extensive engineering and support resources to maintain and reduces the utility and flexibility of each user's computer.
The .NET Framework includes an i