Return to HomePage



Protect Credentials Within a Connection String in Code (C#)


Applies to

* .NET Framework 2.0
* C#
* Server-side code

Summary

The purpose of this code is to offer an alternative mechanism for encrypting database connection string data using the Windows Data Protection API (DPAPI) in .NET source code.

Objectives

* Protect database connection strings credentials using both encryption and access control
* Relegate encryption implementation specifics such as cipher selection encryption modes, key generation and key management to the DPAPI
* Store the data in an easily recoverable and protected fashion in the Windows Registry


Scenarios

* Application does not make use of ASP.NET and therefore does not have a web.config file, such as a client-server application
* Developer wishes to make use of user store, as opposed to machine key, to restrict database credentials access to specific user accounts


Solution Example

public static void StoreConnectionString(string keyName, string valueName, string connectionString)
{
		    		// Convert the connection string to a byte array
		    		// and encrypt the data by using the DPAPI [ProtectedData] class.
		    		byte[] [encryptedConnStrBytes] = [ProtectedData.Protect(]
		                    [UnicodeEncoding.ASCII.GetBytes(connectionString),] 
		                    null, 
		                    [DataProtectionScope.CurrentUser);]
	

		    		// Create a security context for a new key that we will use to store our encrypted connection string.
		    		// The security context will restrict access to only our user.
		    		string user = [Environment.UserDomainName] + "\\" + [Environment.UserName;]
		    		[RegistrySecurity] security = new [RegistrySecurity();]
		    		[RegistryAccessRule] rule = new [RegistryAccessRule(user,]
		                    	[RegistryRights.FullControl,]
		                    	[InheritanceFlags.ContainerInherit,]
		                    	[PropagationFlags.None,]
		                    	[AccessControlType.Allow);]
		    	[security.AddAccessRule(rule);]
	

		    	// Actually create the new registry key and apply the security context we just came up with.
		    	[RegistryKey] key = [Registry.CurrentUser.CreateSubKey(keyName,]
		                    [RegistryKeyPermissionCheck.ReadWriteSubTree,]
		                    security);
	

		    	// Write the encrypted connection string into the registry
		    	[key.SetValue(valueName,] [encryptedConnStrBytes);]
	
}


Problem Example

The following example demonstrates the use of the registry to store a cleartext database connection string.

// Database connection string
string connStr = "Initial Catalog=snippets;Data Source=vm-win2003\\sqlexpress;Integrated Security=SSPI;";

// Store connection string in the registry
RegistryKey key = Registry.CurrentUser.CreateSubKey("PlaintextConnectionString");
key.SetValue("ConnStr", connStr);

* Cleartext connection string details can be viewed by any user with access to the registry
* In a mixed-mode authentication scenario, credentials would be viewable by any user with access to the registry
* Lack of registry ACL's allows all systems users read access to this registry key

Test Case

The following classes must be included in any project making use of the sample code provided above:

using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Security.AccessControl;
using System.Text;
using Microsoft.Win32;

The following test case methods store and retrieve encrypted registry data and output the results to the console.

public static string RetrieveConnectionString(string keyName, string valueName)
{
		    		// Read the encrypted connection string value from the registry 
		    		[RegistryKey] key = [Registry.CurrentUser.OpenSubKey(keyName);]
		    		byte[] [encryptedConnStrBytes] = [key.GetValue(valueName)] as byte[];
	

		    		// Decrypt the encrypted bytes using DPAPI, convert to string and return
		    		byte[] [decryptedConnStrBytes] = [ProtectedData.Unprotect(]
		                     	[encryptedConnStrBytes,] 
		                     	null,
		                     	[DataProtectionScope.CurrentUser);]
		    		[return(UnicodeEncoding.ASCII.GetString(decryptedConnStrBytes));]
	
}

static void Main(string[] args)
{
		    	// A sample connection string we might want to store
		    	string stored = "Initial Catalog=snippets;Data Source=vm-win2003\\sqlexpress;Integrated 	Security=SSPI;";
		    	Console.WriteLine("Stored String: " + stored);
	

		    	// Create an instance of our class and pass the string we want to encrypt
		    	StoreConnectionString("EncryptedConnectionString", "CipherText", stored);
	

		    	// Retrieve from the registry and print to make sure it worked.
		    	// You can also fire up regedit and browse to HKEY_CURRENT_USER\EncryptedConnectionString
		    	// to see the encrypted bytes.
		    	string retrieved = RetrieveConnectionString("EncryptedConnectionString", "CipherText");
		    	Console.WriteLine("Retrieved String: " + retrieved);
	
}


Expected Result

Stored String: Initial Catalog=snippets;Data Source=vm-win2003\sqlexpress;Integrated Security=SSPI;
Retrieved String: Initial Catalog=snippets;Data Source=vm-win2003\sqlexpress;Integrated Security=SSPI;



More Information

This implementation makes use of the DPAPI user key as opposed to the machine key. This means that the connection string will not be accessible by other applications running under different service accounts.
This adds additional protection against a rogue application (such as a virus or Trojan) compromising connection string data but could pose problems where sharing between multiple applications running under different accounts is required.


Additional Resources

* Encrypting Connection Strings using DPAPI (ASP.NET): http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/paght000005.asp
* Encrypting Connection Strings using RSA (ASP.NET): http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/paght000005.asp
* Cryptography (.NET): http://msdn.microsoft.com/library/en-us/dnpag2/html/PAGGuidelines0003.asp?frame=true#pagguidelines0003_cryptography


Attributes

* Applies To: .NET Framework 2.0, C#
* Category: Data Access
* Author: Jonathan Bailey





Return to HomePage
Microsoft Communities