Listed here are the issues and frustrations with the encryption/decryption of a simple connection string and the findings.
Protect a connection string in the App.config file of a Windows Forms app by encrypting it. The app will use Enterprise Library 2.0 and an internal util library used in both Windows Forms and Web apps and deployed via ClickOnce. Simple enough? Right? Wrong!
The first thing I did was to encrypt directly the connection string. Although you have everything you need to encrypt/decrypt right in the .NET Framework, Microsoft didn’t made this operation simple for those who never touched encryption before. You quickly learn that some forms of encryption are tied to the machine where the encryption is taking place. Since I wanted to encrypt, on one machine and distribute the result to multiple clients, I had to select a non-random and non-machine specific method. A quick search lead me to the Obviex site where I found some well documented code:
http://www.obviex.com/samples/Encryption.aspx
I quickly incorporated a version of the above code and tested my app.
A quickly found out that Enterprise Library does not like connection strings that are encrypted. One solution would be to change Enterprise Library source code a little bit but that’s one thing I try to avoid for compatibility reasons. Back to square one.
One cool new thing in the .NET Framework 2.0 is the ability to encrypt a whole section in the configuration file. However, I quickly found out two things:
It’s very easy to encrypt a section in the configuration file, here’s the code:
public static void EncryptConfigSection(string sectionName)
{
Configuration config = ConfigurationManager.OpenExeConfiguration(onfigurationUserLevel.None);
ConfigurationSection section = config.GetSection(sectionName);
if (section != null)
if (!section.IsReadOnly())
section.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider");
section.SectionInformation.ForceSave = true;
config.Save(ConfigurationSaveMode.Full);
}
ConfigurationManager.RefreshSection(sectionName);
What cool is that you don’t have to code anything special to read back the encrypted data. The Configuration Manager figures out that the stuff inside the section is encrypted and decrypts it automatically. Great, but this means that the config file must be deployed non encrypted. In a Windows Forms scenario, that’s bad. So what can you do?
So the encryption must be done locally. How do you do that and of course, when? You can do it the first time that the app will start. However, it leaves you with a small window of time when the information is unprotected. You can let the setup program do it. Hameer Saleem wrote a great article on The Code Project Website explaining how to do that:
http://www.codeproject.com/csharp/ProtectedConfigWinApps.asp
The drawback is that you must use an installer to deploy you app. What if you use ClickOnce?
The files needed to deploy a Windows Forms app with ClickOnce are usually located on a Web server. What if someone could access the config file directly from the Web server? He could have access to our non-encrypted connection string, right? Right!
We found a way to access the config file directly from the Web server without installing the application. Doh!
Challenge #6 - When to encrypt? (part 2)
So, the connection string must be protected before being deployed because of the possibility of a hack but it must be in a way that Enterprise Library can understand.
The solution is then:
Our solution works except for something really unexpected…a bug in the .NET Framework!
The standard way to access a connection string in the connectionStrings section of the config file is by using the static GetSection method of the ConfigurationManager object. The beauty of this method is that it will work in Windows and Web apps. It work beautifully when the connectionStrings section is not encrypted but as soon as it is, the code throws an error when run in a Windows Forms app however, it works in a Web app!
ConnectionStringsSection configurationSection = ConfigurationManager.GetSection("connectionStrings") as ConnectionStringsSection;
string conStringValue = configurationSection.ConnectionStrings[conStringKey].ToString();
Worse, Enterprise Library 2.0 is using the bugged static method!
The bug is documented in this thread:
http://www.developersdex.com/asp/message.asp?p=2911&r=5205960&Page=1
From: Steven Cheng[MSFT]Date Posted: 8/17/2006 8:08:00 AM
Thanks for your reply Rayn,So you got the same test results as mine (test code 1 through error while test code 2 works), correct? Yes, I agree that the problem is not specific to ConfigurationManager, it is the GetSection function and its callee (from call stack it is a recursive fuction which throw the error).Sure, the ConfigurationManager.ConnectionStrings static member also wrapper the "GetSection" method. However, the problem here is that the test result here indicate that the exception somewhat depend on the approach we get the Section. Anyway, I'll perform some further test through custom section since that won't rely on any built-in static properties. I'll update you my test results.Sincerely,Steven ChengMicrosoft MSDN Online Support Lead
From: Steven Cheng[MSFT]Date Posted: 8/25/2006 5:44:00 AM
I did have checked our internal database and this issue has been recorded so far.
However, I think it'll be hard to address it in a short time. If you would like to get a hotfix, you can contact CSS product support for assistance.
So we can request a hotfix but deploying it to hundred of workstations is really an issue and we don’t want to get there.
So the static method is bugged. Is there an alternative? Of course, there is. A quick search resulted in finding the OpenExeConfiguration method of the ConfigurationManager and this one worked on encrypted sections.
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
string = config.ConnectionStrings.ConnectionStrings[conStringKey].ToString();
So it’s just a matter of changing one line of code in Enterprise Library, right? Wrong!
Sure it works in Windows Forms apps but three letters in the method name looks suspicious: EXE. A quick try in a Web app confirmed the suspicion. It is Windows Forms specific and yes, there’s something similar in the System.Web.Configuration namespace but it will work with Web apps only!
So we need to keep Enterprise Library code as generic as it is but make it work with encrypted and non-encrypted connection strings in both Windows Forms and Web apps. Is there a way to force some connection string in Enterprise Library so we could use Windows Forms or Web specific code to retrieve it? Yes but not with the generic database creation method of Enterprise Library:
Database db = DatabaseFactory.CreateDatabase(conStringKey);
Instead, we can use this code that takes a connection string as an argument instead of the key name but it’s less generic:
Database db = new SqlDatabase(conString);
Success!!!
Here’s the final code to retrieve the connection string. Note that you have to specify if the app is a Windows Forms app of a Web app. We did it by passing a hardcoded value (applicationType) but I guess you can found out at runtime if you're running in Win or Web.
public enum ApplicationType
Web, Windows
public string GetConnectionStringFromKey(string conStringKey ApplicationType applicationType)
string ret = string.Empty;
switch (applicationType)
case ApplicationType.Windows:
ret = config.ConnectionStrings.ConnectionStrings[conStringKey].ToString();
break;
case ApplicationType.Web:
ret = configurationSection.ConnectionStrings[conStringKey].ToString();
return ret;
You can then call the specific Enterprise Library database objects and pass the connection string:
public enum DatabaseType
SQLServer, Oracle
Database db = null;
switch (databaseType)
case DatabaseType.SQLServer:
db = new SqlDatabase(connectString);
case DatabaseType.Oracle:
db = new OracleDatabase(connectString);
Remember Me
Theme design by Jelle Druyts
Powered by: newtelligence dasBlog 2.1.8102.813
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way. Since I'm self employed, this mean that these do not represent my own opinions. Gee, go figure!No chipmunks were harmed while coding, deploying and configuring this blog...well, maybe a little bit but not that much. Hey, some of them even enjoyed it. Crazy chipmunks ;-)
Warning: While reading this blog, do not operate heavy machinery, never use a lit match or open flame to check fuel level, don�t try to dry yourself in a microwave oven, do not play in the dishwasher, do not use this blog in any function that involves insertion into a body cavity. Reading in conjunction with alcohol or sedatives may cause drowsiness. May irritate eyes. Use before the expiration date. If you do not understand, or cannot read all directions, cautions and warnings, do not read this blog. Warning - Contents may be hot and under pressure. May blow off causing eye or other serious injury. Point away from face and people, especially while reading. Suitable for vegetarians. This is not a dating agency. Not to be used for anything else. Reading this blog does not enable you to fly. CAUTION: Risk of electric shock - Dot not open. Do not use as an ice cream topping. Not for intimate hygiene.
© Copyright 2009, Guy Barrette
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.
E-mail