microsoft press home   All Products  |   Support  |   Search  |   microsoft.com Home  
 
  Microsoft Press Home  |   Register Books  |   Site Index  |   All Books  |

 

Advanced Search
Hot topics:
Books about:
Books for:
Products for:



Developer Featured Article
Keeping Confidential Information Secure
Keeping Confidential Information Secure

By Scott Mauvais, MCSE, MCSD, MCDBA

Most applications, no matter how trivial, have some sensitive information they need to protect. Obvious examples of sensitive information include user credentials and personal data such as medical and financial records. Even if your application does not consume or store sensitive information, you probably need to protect your application's configuration data such as license keys or file locations lest your application be vulnerable to piracy or denial of services attacks.

Storing confidential information is one of the more vexing problems we developers face. On the one hand, our application needs to access this data, yet we need to prevent unauthorized access to it. The inherent problem is that given sufficient privilege, an attacker can impersonate the application and thus gain access to the protected data. In this article, I will cover some techniques that you can use to write more secure, robust applications by safely storing secrets in your applications. Although I will focus mainly on applications built for the Microsoft� .NET Framework, most of the techniques are relevant to classing Win32� programs also.


Storing secrets is just a small part of building secure applications. For a more thorough discussion of the topic, you should pick up a copy of Michael Howard and David LeBlanc's new book, Writing Secure Code. The book covers everything from preventing buffer overruns to controlling access to testing security. They even have an entire chapter devoted to storing secrets. To get a feel for the book, you can review the table of contents and read a Chapter 12: Securing Web-Based Services on the Microsoft Press� site. To dive into even more detail, you will want to read Michael Howard's previous book, Designing Secure Web-Based Applications for Microsoft Windows� 2000, for which you'll also find a table of contents and Chapter 5: Internet Information Services Security Overview at the Microsoft Press site. Michael is a program manager on the Windows 2000 security team, so he provides unique insight into making the most out of the Windows 2000 security model. David is a senior security technologist in Microsoft's Information Technology Group, where he focuses on defending the Microsoft network from attack.

        

Just Don't Do it

Relax, the best solution to storing secrets is the easiest one: Don't store them in the first place. Storing sensitive data is risky, and you should treat secrets just like you do any other risk. The first technique in risk management is to transfer the risk to somebody else. Rather than spending resources trying to figure out how to protect confidential information, you are better off trying to figure out how not to store it in the first place.

This approach has a number of benefits. First off, it reduces the attack surface: the fewer places information is stored, the less likely it is to leak out. Second, it reduces the resources you need to spend developing your application and thus allows you to either ship sooner or add in more features�either way, you win. Third, when you centralize the storage of sensitive information, you can focus resources on protecting that one instance and auditing its usage.

Sure, the benefits sound great, but how exactly does one go about transferring the risk to someone else? As an example, let's look at what is probably the most common secret that applications store: passwords. If you are in a Microsoft Windows environment, there are very, very few cases in which you should be managing passwords in your applications. Rather, you should rely on Microsoft Windows Authentication. Besides the benefits transferring risk that I mentioned earlier, using Windows Authentication lets you leverage all the great features of Microsoft Windows password management such as aging, minimum complexity, and account lockouts. To learn more about Microsoft Windows Authentication, see the Security Support Provider Interface section of Jeffrey Richter's Programming Server-Side Applications for Microsoft Windows 2000.

If you can't rely on Microsoft Windows password management for some reason�for example, if you need to pass credentials through a firewall and the security policy forbids opening up the required ports�another approach is to store a verifier rather than the password itself. Under this approach, you store something you can use to verify that the user knows the password. A common approach is to hash the password and then store the hash rather than the password itself. When a user enters his or her password, you hash it and compare the output of your hashing algorithm to the hash you stored. If they match, then you can be sure the user knows the password. The benefit of this approach is that even if your application is compromised, all the attacker gets are the hashes, rather than the passwords themselves. For more information on this technique, see the "Storing Secrets" chapter in Writing Secure Code, by Michael Howard and David Le Blanc's. Incidentally, this is how Microsoft Windows Authentication works: a user's password is never placed on the wire; rather, only a hash is sent across the network.

 

Make It Hard

Unfortunately, you can't always take the easy way out, and there are times when you will have to store secrets. If transferring the risk is not feasible, the next best strategy is to minimize the likelihood that a loss will occur. For example, maybe you need to access a back-end system that is not (gasp!) running on Microsoft Windows, or it is your application that will be the system of record for some sensitive information, and you want to encrypt that data. While these examples may seem fundamentally different, the approach is the same: you want to reduce the probability of exposing the sensitive information by encrypting it. (You weren't going to store that non-Windows password in clear text were you?) This should be pretty easy. All you need to do is pick a strong encryption library, encrypt the data, and then save it to your favorite persistent store. If you are feeling particularly dutiful, you might even add an extra level of protection and use an access control list (ACL) to protect the ciphertext so that only authorized users can access it. Simple enough, right?

Well, not quite. Can you spot the flaw in this reasoning? It is a common belief that encryption is the solution to the problem of storing secrets. Actually, it's only half of the solution.

The part that is missing is you still need to protect the encryption key. If an attacker gains access to your key, all those CPU cycles you spent encrypting that data are for naught because he or she can just use that key to decrypt it. As I mentioned in my introduction, the fundamental problem here is that a privileged account can access any part of the system, so no matter where you store an encryption key, it is vulnerable to a rogue administrator or an attacker that has so compromised the system that she or he has gained enough privilege to access it.
One way to make it more difficult for an attacker is to use the Data Protection API (DPAPI) included in Microsoft Windows 2000 and later.

Data Protection API

Let's look at some of the advantages of using the DPAPI over some other encryption techniques. First, it's part of the underlying operating system, so this means you can count on DPAPI being installed on every (Microsoft Windows 2000 and later) machine. Better yet, it supports the concept of transferring the risk because you don't need to worry about it. The second advantage is that you don't have to worry about storing the encryption key. Describing exactly how the encryption key is generated and stored is out of the scope of this article but at a very high level, the DPAPI generates the encryption key based on a preexisting secret�the user's password. While this is an over-simplification of the process, it will work for the purpose of this article. To learn how the process really works, you can find an excellent discussion on the topic in the Windows Data Protection white paper available on MSDN�.

Using the DPAPI is pretty easy because it contains only two methods: CryptProtectData and CryptUnprotectData. To encrypt data, pass the clear text into CryptProtectData, and it will return the ciphertext. To decrypt, simply reverse the process by passing the ciphertext to CryptUnprotectData, and it returns the clear text. Because the DPAPI leverages the user's credentials when generating the key, users logged on with different accounts will receive different output, so you don't need to worry about protecting data from other users on the same system.

If you are familiar with using the Local Security Authority's (LSA) LsaStorePrivateData and LsaRetrievePrivateData, there are some important differences you need to be aware of. First, DPAPI does not actually store or retrieve the secret for you. Rather it simply encrypts and decrypts; storage is up to you. Overall, this is a good thing because now you can store the secrets using whatever means is most appropriate for your application�you just need to remember to do it because the API does not do it automatically. Second, while the LSA has a limited number of secrets it can store (4096, and half of these are reserved for the operating system), there is no such limit on the DPAPI. Finally, a user does not need administrative privileges to call the DPAPI, so you can adhere to the least-privilege principle when designing your application.

 

DPAPI and the Microsoft .NET Framework

The DPAPI is part of the Cryptography API (Crypto API) and is implemented in crypt32.dll, which is native code. If you want to use it from managed code such as Microsoft Visual Basic� .NET or Visual C#�, you will need to use P/Invoke. The resource CD that is included in Howard and LeBlanc's Writing Secure Code contains some sample code that wraps the DPAPI in managed code.

If you want to use the DPAPI from an ASP.NET application, you need to take a couple of other things into consideration. Because the DPAPI relies on an account password to create the encryption key, it needs to load a user profile. Unfortunately, the ASPNET account does not have a user profile. (Astute readers may want to try having the Web application impersonate the caller, but this will not work either. This will give the thread an impersonation token that is a network logon session, and network sessions do not load the user's profile.)
Rather than using a user account for the encryption, the DPAPI supports using the machine account by passing the CRYPTPROTECT LOCAL MACHINE flag when you call the DPAPI methods.  The drawback here is that the secret is no longer tied to the user; it is tied to the machine. This means that any process running on the machine�say an app placed there by the attacker�is able to decrypt your secret. Of course, you could ACL the file or registry key where you stored the encrypted text to prevent unauthorized access to it. However, a user with sufficient privilege can easily reset your ACLs.

A better approach is to use an Enterprise Services (COM+) application and have it call the DPAPI. Using this approach, first create an Enterprise Services application that wraps the DPAPI calls and install it with a fixed identity that will give it access to a user profile. At runtime, your Microsoft ASP.NET application retrieves the encrypted string and passes this string to a method on your Serviced Component. The component then P/Invokes the DPAPI, passes it the cipher text, and returns the clear text to the Web application. Diving farther into the details of this approach is outside the scope of this article, but this should provide enough information to get you started. Tim Ewald's article, COM+ Integration: How .NET Enterprise Services Can Help You Build Distributed Applications, on MSDN provides some great background on enterprise services.

For More Information

If you remember nothing else from this article, remember this: try not to store secrets in the first place. When you are presented with a secret you think you need to store, the first thing you should do is reexamine your application's design and verify that you really do need to store it. If you do need to store it, use Microsoft Window's built-in encryption functions such as the DPAPI rather than trying to implement your own. Finally, remember that you need to do your best to protect yourself against not only outside attackers but also rogue administrators, so you will want to use a defense in-depth approach.

As I mentioned at the beginning of the article, the best place to learn about developing secure applications is to read Michael Howard and David LeBlanc's new book, Writing Secure Code. You might also want to check out the following Microsoft Press resources, which provide in-depth documentation for all issues related to developing secure applications:

Microsoft Press provides in-depth documentation for these and all the other issues related to developing for .NET. For a complete list of .NET titles from Microsoft Press, see the Inside Information About Microsoft .NET page.

Top of Page
 
Last Updated: Monday, September 30, 2002