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