Introduction
This short article shows how you can easily encrypt/secure only the password segment of the connection string in an app.config file. The same technique could easily be adopted to hide any other attribute of application type settings in a .NET configuration file.
Background
I have used security providers in the past to secure connection strings in app.config of many .NET applications. Using a built-in mechanism hides the whole section rather than just one attribute. Recently I came accross a situation were hiding the whole section was not acceptable and therefore I only had to hide the password. After searching the web I decided to go for a handcrafted solution.
Since app.config is a plain XML file I decided to treat it as such. My solution loads the app.config into an XmlDocument
, uses XPath to find the relevant node (connectionString
), loads the connection string into a SqlConnectionStringBuilder
, encrypts the password, gets the updated connection string from the builder, updates the XmlDocument
, and then saves it back to the original file path.
Using the code
The code below is not a full implementation, you will have to completely encrypt and decrypt methods. The decrypt method should return an empty or null string if the password can't be decrypted or if it is not encrypted.
You should only call GetConnectionString
once as early as possible in your application start up procedure and store the connection string in a property or something else that you may get access to easily at a later stage.
class Program
{
static void Main(string[] args)
{
string connString = GetConnectionString("dbConn");
Console.WriteLine(connString);
Console.ReadKey();
}
static string GetConnectionString(string connName)
{
string connString = string.Empty;
string configPath = Process.GetCurrentProcess().MainModule.FileName + ".config";
XmlDocument doc = new XmlDocument();
doc.Load(configPath);
XmlNode node = doc.SelectSingleNode("configuration/connectionStrings/add[@name = \"" + connName + "\"]");
if (node != null)
{
XmlAttribute attr = node.Attributes["connectionString"];
if (attr != null)
{
SqlConnectionStringBuilder csb = new SqlConnectionStringBuilder(attr.Value);
string clearPass = Decrypt(csb.Password);
if (string.IsNullOrEmpty(clearPass))
{
connString = csb.ToString();
csb.Password = Encrypt(csb.Password);
attr.Value = csb.ToString();
doc.Save(configPath);
}
else
{
csb.Password = clearPass;
connString = csb.ToString();
}
}
}
return connString;
}
static string Encrypt(string value)
{
throw new NotImplementedException();
}
static string Decrypt(string value)
{
throw new NotImplementedException();
}
}
Points of Interest
- The best thing to note is that you can override the encrypted password with a new one anytime and it will be encryped the next time the application starts.
- This solution works well in upgrade situations where the connection string and the password are not secure, on the first run it will seamlesly encrypt the existing passowrd.
- Securing only the passowrd allows users to see other non-critical data in the string.
- If you use ConfigurationManager to get your string after this code has run your connection will fail since the passowrd is encrypted.