Using C# to Encrypt and Decrypt .Net Connection Strings

There are several ways to secure an IIS web application on Windows Server such as using an SSL certificate, a Firewall, access control lists (ACL), and using an application pool identity.  These are standard security techniques that should be implemented as part of ‘best practices’ but encrypting connection strings is an additional security measure you may not have considered.  Since config files for asp.net applications are plaintext, anyone with access to the server has the ability to see the database username and password.  Fortunately on Windows web servers you just need to run the ASP.NET IIS Registration tool (aspnet_regiis.exe) to encrypt and decrypt app config connection strings or other sections of the config file.

 

image

 

Encrypting connection strings with aspnet_regiis.exe

In a previous post I covered how you can easily encrypt and decrypt connection strings using aspnet_regiis.exe. However, it is a manual process that usually involves creating batch files and requires hard coding application names and paths. Speaking from personal experience this becomes a cumbersome task if you’re managing a shared hosting server with multiple sites.

Key not valid for use in specified state error

Before getting started it is important to understand that when you encrypt config sections the encryption key is unique to the server where the encrypting was performed. This means if you encrypt the config and then move it to another server i.e a web farm and try to access your application you’ll get the error Failed to decrypt using provider…Key not valid for use in specified state. The only way around this is to create your own RSA container and then perform the encryption with that key and then install it on each server where your encrypted config file will be used.

Encrypt connection strings using aspnet_regiis.exe:

aspnet_regiis.exe -pef "connectionStrings" "d:\sites\site1.com"
-prov "DataProtectionConfigurationProvider"

 

Decrypt connection strings using aspnet_regiis.exe:

aspnet_regiis.exe –pdf "connectionStrings" "d:\sites\site1.com"

 

Create your own RSA container:

aspnet_regiis -pc "MyFarmKey" –exp

Encrypt connection strings using your own RSA container:

aspnet_regiis.exe -pef "connectionStrings" "d:\sites\site1.com"
 -prov "MyFarmCrypto"

 

Export your RSA container to a file for installing on another server:

aspnet_regiis -px "MyFarmKey" "d:\temp\MyFarmKey.xml" –pri

 

Import the RSA container on a new server:

aspnet_regiis -pi "MyFarmKey" "D:\temp\MyFarmKey.xml"

 

Assign your site’s app pool permission to the new RSA container:

aspnet_regiis -pa "MyFarmKey" "iis apppool\site1.com"

 

 

Encrypting Configuration Information Using Protected Configuration

To solve my challenge of multiple hardcoded batch files I created a .Net Windows Form to dynamically read all the sites on an web server and then either encrypt or decrypt the connection strings with a click of a button. And when the connection string is decrypted you can edit the values as needed. Encrypting the connection string again will then update the config with the new values that were entered. On my test server I have 4 sites configured.

image

 

Creating a Windows Form is pretty straight forward. I run it from the command line on the server. When the application opens it will add an entry in the pull down menu for each site configured in IIS. Alternatively if IIS is not installed on the server but there are .Net applications you clicking the Open button will open a file picker tool to select the file you want to manage.

aspnet-config-encryption-decryption-site-list

 

To read the IIS sites on the server just use the Server Manager Class and Application Class in Microsoft.Web.Administration. Each entry of the combobox stores the site’s application path.

public  void listSites()
       {
           ServerManager mgr = new ServerManager();
           foreach (Site s in mgr.Sites.OrderBy(x => x.Name))
               foreach (Microsoft.Web.Administration.Application app in s.Applications)                                 
                   if (app.Path=="/")
                       comboBoxApps.Items.Add(s.Name);
                   else
                       comboBoxApps.Items.Add(s.Name + app.Path);
       }

 

Selecting one of the sites in the menu will then read the config file allowing you to encrypt or decrypt the connection strings.

aspnet-config-encrypt-connection-strings

 

To read the connection strings you have to access the config file using the file path obtained in the previous step.

ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = filePath;
System.Configuration.Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);

ConnectionStringsSection connSection = config.GetSection("connectionStrings") as ConnectionStringsSection;
stem.Configuration.ConfigurationSection secureAppSection = config.GetSection("secureAppSettings");

 

If the connection strings are protected i.e encrypted then decrypt them.

if (config.ConnectionStrings.SectionInformation.IsProtected) //config is encrypted
    config.ConnectionStrings.SectionInformation.UnprotectSection();

 

Once the section is decrypted loop through the connection strings loading the values into a textbox on the form.

foreach (ConnectionStringSettings connString in connSection.ConnectionStrings)
 {    
 TextBox txt = new TextBox();
 txt.Name = "txtConnStr" + "_" + connString.Name;
 txt.Text = config.ConnectionStrings.ConnectionStrings[connString.Name].ConnectionString.Trim();
 this.Controls.Add(txt);
 }

 

After reviewing the decrypted connection strings or editing the values just save the data back to the config file and encrypt the settings again.

ProtectedConfigurationSection section = config.GetSection("configProtectedData") as ProtectedConfigurationSection;
ProviderSettingsCollection providerSettings = section.Providers;

config.ConnectionStrings.ConnectionStrings[SQLConn].ConnectionString = txtConnStr.Text.Trim();

connSection.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
connSection.SectionInformation.ForceSave = true;
config.Save();

 

When the config file is encrypted a message is displayed indicating as such and the button action is reset to decrypt the connection strings.

aspnet-config-decrypt-connection-strings

 

In Summary

Encrypting Configuration Information Using Protected Configuration is a great way to add an additional level of security to sensitive information in an application config file. Before encrypting config sections remember that the key is unique to the server where the encryption is performed. If you need to deploy the config file to multiple servers create a custom RSA container and install that on each server to prevent invalid key errors. Thanks for reading!

Peter Viola

Creative, customer focused, results oriented, Senior Web Systems Engineer who enjoys providing the highest level of customer service supporting complex Windows hosting solutions. MCITP, MCSA, MCTS

More Posts - Website