Click here to Skip to main content
15,879,326 members
Articles / Web Development / IIS
Article

DPAPI and Triple DES: A powerful combination to secure connection strings and other application settings

Rate me:
Please Sign up or sign in to vote.
4.77/5 (47 votes)
26 Aug 20056 min read 133.1K   1.7K   85   23
This article shows how DPAPI and Triple DES can be used to encrypt connection strings and other sensitive strings for storage in the ASP.NET web.config file.

Introduction

I think that at some point all ASP.NET developers are faced with the question of how to protect sensitive data stored in the web.config file. I recall a few years back in my first ASP.NET interview I was asked: "How would you secure a connection string containing passwords in the .config file?" I, maybe a little naively, replied that you can just put the connection string in there unencrypted as .config files are anyway not served by IIS.

Although the above statement is more or less correct you do however soon realize that this strategy simply won't do once the security conscious start tearing your code apart. In this article, I will attempt to recover from my "shameful" statement and will provide an easy to implement solution that is as close as possible to the Microsoft's best practice.

A common solution

A simple solution to the problem is to use .NET to encrypt the connection string stored in the .config file using an algorithm like the Triple DES or something similar. The application will read the encrypted value from the .config file and decrypt it again to retrieve the plain text.

This solution works very well and in this article I basically do exactly the same thing. The only problem with this approach is that you always end up with a key management issue. Just where do you store your decryption key to keep it safe? In this article, I will show how to keep the key reasonably safe using the Microsoft Data Protection API.

Impersonation

Commonly, we want to protect a username and password combination in the .config file which is used to impersonate a user with appropriate rights while trying to access SQL Server or a web service requiring authentication. In a situation where integrated Windows authentication can be used for accessing protected resources the following elegant solution can be implemented:

Add the following line in the <system.web> section of your web.config file:

XML
<identity impersonate="true" />

This line tells ASP.NET to impersonate the user who is accessing the site. If you turn off anonymous access for the application this will be the credentials that the user supplied when accessing the site. This is all you need to do if you know that all users will access the site using Integrated Windows authentication and that the user's credentials will have access to all the SQL Servers and web services that will be accessed by the application.

A better solution might however be to have a single user that will be used on behalf of the ASP.NET application to access the protected resources. In this situation simply allow anonymous access on the site and change the user account of the anonymous user to an account that will have the appropriate access to the protected resources.

Image 1

Aspnet_setreg

Microsoft realized that we don't like storing unencrypted credentials in the web.config file and provided the aspnet_setreg utility to encrypt and store impersonation identity and the connection string for the session state in the registry under a secure key.

This implementation uses DPAPI to encrypt and decrypt the settings that should be secured. Please note that this implementation passes the CRYPTPROTECT_LOCAL_MACHINE flag to CryptProtectData and CryptUnprotectData functions which means that Local Machine storage is used. You should therefore be aware that this is not the safest possible solution since anyone with local machine access will therefore potentially be able to decrypt these values. However what is used to make this implementation secure is a strong Discretionary Access Control List (DACL) that is applied to the registry key.

Using this utility is very simple, first download it from here and extract it to a location convenient for you. Once extracted run the application and supply it with a registry location and the username and password that you would like your application to impersonate:

aspnet_setreg.exe -k:SOFTWARE\MY_SECURE_APP\identity 
               -u:"yourdomainname\username" -p:"password"

After executing this command you will receive an output similar to that given below that will instruct you how to use the key and secure it.

Please edit your configuration to contain the following:

userName=
 "registry:HKLM\SOFTWARE\MY_SECURE_APP\identity\ASPNET_SETREG,
                                                     userName"
password=
 "registry:HKLM\SOFTWARE\MY_SECURE_APP\identity\ASPNET_SETREG,
                                                     password"

The DACL on the registry key grants Full Control to System, 
Administrators, and Creator Owner.

If you have encrypted credentials for the <IDENTITY /> 
configuration section, or a connection string for the <sessionState/> 
configuration section, ensure that the process identity has
Read access to the registry key. Furthermore, if you have 
configured IIS to access content on a UNC share, the account used 
to access the share will need Read access to the registry key.
Regedt32.exe may be used to view/modify registry key permissions.

You may rename the registry subkey and registry value in order to 
prevent discovery.

The next step that must be performed is setting up the DACL for the registry key to allow ASP.NET to read it:

Image 2

Finally, you can add the impersonation line to your web.config that uses the values you received in the previous step. Also ensure that all your connection strings use integrated Windows security.

XML
<identity impersonate="true"
userName=
 "registry:HKLM\SOFTWARE\MY_SECURE_APP\identity\ASPNET_SETREG,
                                                     userName"
password=
 "registry:HKLM\SOFTWARE\MY_SECURE_APP\identity\ASPNET_SETREG,
                                                  password" />

Currently, this approach seems to be the Microsoft recommended best practice, but unfortunately this security mechanism is very limited in terms of the fact that it only allows you to securely store credentials for impersonation and Windows Integrated security. What is sometimes needed is a more generic approach that will allow you to store any sensitive encrypted data in the web.config file.

The solution that I propose to this problem is a combination of the approach just discussed and the encrypted strings approach. My approach assumes that the way credentials are stored in the registry and protected by the DACL is indeed the most secure protection offered to us by Microsoft.

DPAPI and Triple DES

The idea behind my solution is very simple, use the DPAPI and a DACL in exactly the same way as aspnet_setreg.exe does to store a master key in the registry that will be used to encrypt and decrypt sensitive data. This secure master key OS is then used with the Triple DES algorithm to encrypt and decrypt the values in the .config.

The first step is to store the master key in the registry, simply run the Windows application executable, Foulds.Security.UserInterface.DataProtection.exe, and use it to configure the registry key location and store it in the registry. After clicking on the Save button click on the Load button to ensure that the key can be loaded from the registry.

Image 3

After the master key is stored in the database you can encrypt the values that should be stored in the web.config file. Enter the value in the plain text box and click encrypt, the result in the Cipher Text box can then be copied to the registry.

As with the aspnet_setreg utility you will have to configure the DACL for the registry key you have created to allow ASP.NET to read it.

A special section handler has been created to simplify the encryption and decryption of sensitive data. To enable this section handler add a reference to the Foulds.Security.dll assembly in your web project.

Next add the section handler to your web.config file:

XML
<configSections>
  <sectionGroup name="fouldsSettings">
    <section name="encrypted" 
      type=
       "Foulds.Security.SectionHandlers.DataProtection.SectionHandler, 
                                                    Foulds.Security"/>
  </sectionGroup> 
</configSections>

You then have to add the configuration section to your web.config file that will specify the location of master key in the registry and the encrypted key value pairs for your application. Below is a sample of the configuration section:

XML
<fouldsSettings>
    <encrypted registryKey="SOFTWARE\HannesFoulds\encryption,
                                                  masterkey">
        <add key="secret1" value="aVvjoiS42p8=" />
        <add key="secret2" value="mWMSMkNFLSM=" />
        <add key="secret3" value="xwc3jnQ9Zfw=" />
    </encrypted>
</fouldsSettings>

When you want to get the unencrypted value from this configuration section you can use the provided helper class in the Foulds.Security assembly like this:

[Editor Note: Line breaks used to avoid scrolling]

C#
string secret2 = 
  Foulds.Security.SectionHandlers.DataProtection.
                 ConfigSettings.Encrypted["secret2"];

Conclusion

This solution is by far the best way I have come up with to protect sensitive data in the web.config. Please feel free to scrutinize my code and help me make it better. Also if you would like me to flesh out this article with more technical details let me know, it's Friday afternoon now and I'm planning to go home soon ;-)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
South Africa South Africa

Comments and Discussions

 
QuestionImplementation question Pin
Lee Forst31-Aug-05 12:08
Lee Forst31-Aug-05 12:08 
AnswerRe: Implementation question Pin
Hannes Foulds31-Aug-05 21:02
Hannes Foulds31-Aug-05 21:02 
Thank you for your comments on the article. The DPAPI is encrypted for storage in the registry in the same way that the aspnet_setreg utility does - with Machine Store. If you had read up on the DPAPI you will immediately start to think that that can’t possibly the most secure since any user that has local access to the machine will be able to decrypt these values. This is indeed true, and this is exactly why I keep stressing the importance of your DACL of your registry key.

Logically the next question will be why I don’t simply change my application to use User Store for encrypting/decrypting the master key in the registry. I believe that the reason that Microsoft don’t do it in their implementation (and therefore I don’t either) is that it is very problematic using DPAPI with User Store in an ASP.NET application as the account under which ASP.NET runs does not load a user profile that is needed for User Store.

Microsoft has provided us with a way the encrypt/decrypt values with DPAPI using the User Store, you can view this article at:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secmod/html/secmod23.asp

To brutally simply things: In the solution that this article provides you have a COM+ Component (Enterprise Service) that runs under a specific preset user account and the ASP.NET application then calls on this Enterprise Service to provide the encryption/decryption services. To begin with I think that this solution can be a pain to implement for ASP.NET applications as you need to install and configure the COM+ Component and run it under a specific account, and then also install and configure a Windows Service under a specific account to initialize the COM+ Component. Besides installation being a pain in the butt, which we can perhaps live with for the sake of security, the reason why I chose not to use this is because I think it is pointless, my logic goes like this:

My motivation for wanting to use User Store is to provide additional security to ensure that nobody except the user that runs your ASP.NET application can decrypt the master key. If you want to employ User Store from your ASP.NET application you will have to do this through a COM+ Component that always runs under a preset account. In my view you therefore just added additional points of failure to your application (the windows service, and the enterprise service) and are left with exactly the same problem you tried to fix – Now despite the fact that you are using User Store ANYBODY that has access to your machine will STILL be able to decrypt your master key simply by using the Enterprise Service!!

I would like to just explicitly state that the above is my interpretation of things and if it is wrong I really would like to get feedback.

To answer your second question (sorry for beating about the bush a little, just trying to clarify the article a little):
You are correct in stating that the Windows Forms utility will have to be run on each server that will host your application in order for the master key to be placed in the registry. Because Machine Store is used the cipher text for the master key will be unique for each server, so this value cannot be copied to another server and have to be re-created for each of your application servers that host the application– this is also why I don’t use the DPAPI to encrypt the values stored in the web.config. If the values in the web.config were encrypted using DPAPI then you also could not have copied the web.config file to another server since it would not have been possible to decrypt the values on any other server. But since I chose to encrypt the values in the web.config file with Triple DES you can simply copy your web.config file and the server will be able to decrypt these values as long as you use the utility to store the same master key in the registry.

The key/value pair management issue you are referring to when deploying form for example staging to live with different SQL Connection strings is the same you are faced with if you were not using my section handler – I haven’t really come up with a clever solution to this so in my applications I would also comment/uncomment the appropriate values as you suggest. If you do however know beforehand what your connection strings will be in your different environments you can create the encrypted strings for them on your development environment if you are going to use the same master key across your deployments.

I hope my mad ramblings made some sense to you and answered your questions, please let me know if you need more clarification, and I would love to hear your opinion on all this!

GeneralRe: Implementation question Pin
JVMFX19-Oct-05 9:42
JVMFX19-Oct-05 9:42 
GeneralRe: Implementation question Pin
Hannes Foulds19-Oct-05 20:06
Hannes Foulds19-Oct-05 20:06 
GeneralRe: Implementation question Pin
21-Oct-05 1:39
suss21-Oct-05 1:39 
GeneralRe: Implementation question Pin
snickers12313-Jan-09 17:53
snickers12313-Jan-09 17:53 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.