Storing Secrets
Total Page:16
File Type:pdf, Size:1020Kb
C04623317.fm Page 71 Friday, August 25, 2006 3:37 PM Chapter 4 Storing Secrets In this chapter: Identifying Attacks and Attackers . .71 Cryptography to the Rescue?. .72 Hashing Data . .73 Storing Passwords . .75 Encrypting Data . .78 Using the Windows Data Protection API . .107 Protecting Configuration Data . .109 Protecting ViewState. .116 Summary . .119 In most applications, you have to deal with sensitive data. This often involves personal data (for example, postal addresses, telephone numbers, medical records, payroll data, and credit card or social security number information), intellectual property, passwords, or configuration data (for example, connection strings). These “secrets” are stored in various formats (for example, database entries or data or configuration files) and are transmitted by using several protocols (for example, HTTP, TDS, and LDAP). This chapter covers the various primitives of cryptography that enable you to secure sensitive data and shows the design and security implications of these approaches. It also covers the built-in protection mechanisms of the Microsoft .NET Framework such as the Data Protection API and the protected configuration feature. This chapter cannot give you a “proper” introduction to cryptography because that would be a book on its own. Nevertheless, I want to show you which technique to choose in which situation and the “gotchas” you can run into. For those who want to extend their crypto- knowledge beyond what’s presented in this chapter, I highly recommend Practical Cryptography by Niels Ferguson and Bruce Schneier (Wiley Publishing, Inc., 2003). Identifying Attacks and Attackers Data is probably the most precious asset that your company and your application deals with. There are various threats to this asset: ■ Disclosure Some data is highly confidential, such as credit card numbers and medical records, and should be viewable/editable only by authorized people. Data can be 71 C04623317.fm Page 72 Friday, August 25, 2006 3:37 PM 72 Developing More-Secure Microsoft ASP.NET 2.0 Applications disclosed in various ways. Code defects such as SQL injection and directory traversal can enable attackers to access data stored on hard disks or in databases. Data that is transmitted unprotected (for example, plain HTTP or nonsecure database connections) can be disclosed by eavesdropping. ■ Tampering Data tampering is often considered even more harmful than disclosure. If an attacker manages to sniff your five-book order at Amazon.com, it might be bad. But it is much worse if the attacker can modify this order to 50 books without someone noticing the manipulation. Sensitive data should always be stored in a way that only authorized persons or processes are allowed to modify. Furthermore, you should have a clear understanding of which types of attackers you want to protect your data against: ■ External attackers These attackers come from outside your firewall and exploit flaws in the application and network/operating system security configuration. Such flaws can be mitigated by writing robust code, doing proper input validation, and implementing a hardened operating system and network infrastructure. ■ Insiders These are people who work behind your firewall and who might have legitimate access to application files and data (for example, employees such as administrators or developers; contractors; or external consultants). It is especially hard to guard against this type of attacker because they can operate from parts of your network that are often considered trusted. And even if they don’t actively try to compromise your application, data such as payroll information in human resources systems should not be visible to anyone besides authorized personnel. Effectively securing such scenarios always involves introducing paper-security policies in addition to technical countermeasures. For example, the admin of a key store shouldn’t also be the admin of the store where encrypted data using that key is stored (this is called the segregation of duties principle). Cryptography to the Rescue? Cryptography is a technology based on mathematics that can help add the following “features” to data: ■ Confidentiality Data can be read only by the intended people or processes. ■ Integrity Data cannot be modified without notice. ■ Authenticity Who created or changed the data can be verified. It is very important to notice that most of the time, encryption does not eliminate your secrets, but it can reduce the problem of protecting big secrets, such as a data file, to one of protecting a small secret called a key. Your job is to securely generate, store, and transmit those keys. Insecure key management is far more often the weak spot in an application than cryptography is. C04623317.fm Page 73 Friday, August 25, 2006 3:37 PM Chapter 4 Storing Secrets 73 Furthermore, cryptography uses two independent primitives to achieve its goals: hashing and encryption. Hashing is used for integrity, encryption for confidentiality—for authenticity, you have to use a combination of the two. Throughout this chapter, I describe various applications of cryptography to secure data, starting with the basic APIs for hashing and encryption and working through to higher level crypto- graphic application services such as the protected configuration feature of Microsoft .NET Framework version 2.0. Hashing Data Hashing is a deterministic mathematical one-way function used to create a cryptographically secure fingerprint of data. The properties of a hashing algorithm are the following: ■ Fixed-length output Hashing algorithms produce a fixed-length output regardless of the size of the input data. The output length differs with the algorithm used. ■ One-way function Hashes are easy to compute, but difficult to revert. The fixed-length output implies that data is lost during the hashing process (at least when the input data is bigger than the fixed-length output is). Of course, other attacks such as brute force or dictionary attacks recover the plain text. Depending on the probability distribution of the plain text, this is most likely infeasible. ■ Deterministic The hash output is always the same for a given input. ■ Collision free (almost) No feasible way to produce the same hash by using different input values should exist. Good hashing algorithms produce radically different output even if the input is changed only slightly. Hashing is often used to create fingerprints of data; for example, you can store the hash of data and later check whether the data was modified by comparing the stored hash to the current one. Hashing can also be used to provide a secret equivalent. For example, if someone has to prove knowledge of a secret, such as a password, you need only store the hash, not the actual secret. This is discussed in more detail in the section titled “Storing Passwords” later in this chapter. Hashing Algorithms Several hashing algorithms are out there; the most well-known probably are MD5 and SHA1. If you want an easy introduction to how they work internally, have a look at Practical Cryptography. All .NET classes that implement hashing algorithms are derived from HashAlgorithm and can be found in the System.Security.Cryptography namespace (see Figure 4-1). Weaknesses have been found in MD5, RIPEMD, and SHA1; if possible (for example, when building a new system that need not be compatible with other applications that use these algorithms), you should avoid using them. The currently recommended algorithms are SHA256–SHA512. (SHA384 does not really give you anything—most implementations C04623317.fm Page 74 Friday, August 25, 2006 3:37 PM 74 Developing More-Secure Microsoft ASP.NET 2.0 Applications internally create a SHA512 and throw away the unneeded bits.) The algorithms also differ in the output length: SHA1 produces 160 bits output, whereas SHA256 and SHA512 produce 256 and 512 bits, respectively. You can read more about recommended cryptography algorithms on the NSA home page (http://www.nsa.gov/ia/industry/crypto_suite_b.cfm). HashAlgorithm MD5 MD5CryptoServiceProvider RIPEMD160 RIPEMD160Managed SHA1 SHA1Managed SHA1CryptoServiceProvider SHA256 SHA256Managed SHA384 SHA384Managed SHA512 SHA512Managed Figure 4-1 Hashing algorithms in .NET More Info Class names that end with CryptoServiceProvider indicate that they are a wrapper around the native Microsoft Windows Crypto API, whereas those that end with Managed mean that the implementation is done in managed code. To avoid platform dependencies, choose the managed implementations. (The native ones are considerably faster, though.) Hashing in .NET Creating a hash is very straightforward. Create an instance of a class that implements the hashing algorithm and call the ComputeHash() method. The hash classes work on byte arrays as inputs and outputs. If you have to deal with string data, first you have to encode the string to a byte array. Classes in the System.Text namespace help you do that. Depending on the input character set, you should encode the string by using either UTF-8 or Unicode. string simpleHash(string data) { // Encode data to a byte array. byte[] dataBytes = Encoding.UTF8.GetBytes(data); // Create the hash. SHA256Managed sha = new SHA256Managed(); byte[] hashBytes = sha.ComputeHash(dataBytes); // Return base64-encoded string. return Convert.ToBase64String(hashBytes); } C04623317.fm Page 75 Friday, August 25, 2006 3:37 PM Chapter 4 Storing Secrets 75 This code example produces the following hash for the string hello: LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=