Click here to Skip to main content
Click here to Skip to main content
Go to top

Securing Configuration Files in ASP.NET

, 7 Mar 2011
Rate this:
Please Sign up or sign in to vote.
Securing configuration files in ASP.NET

The Problem

Majority of .NET applications and web-sites store configuration settings in the .config file. The file is an XML file, and can be easily consumed from any .NET application using System.Configuration library. The file frequently contains sensitive configuration settings such as authentication and authorization.

For instance, database connection string is frequently stored in application settings section as key/value pair:

<add key="MyConnectionString1" value="server=db1;
uid=readonlyuser;pwd=secret;database=topsecret;/>

By default, .config files are stored in plain text and can easily be read by anyone who has access to the server/application.
“So what!”, “Why is that a problem at all?”

Here are a few examples why that can actually be a huge problem.

  1. Many web applications have database servers that reside on a different machine from the web-server. It is done for security reasons and to improve performance. Since anyone who gets access to your web-server will easily read your configuration file, he will get access to your database server. And that might be highly undesirable because the database might contain usernames, e-mails, and other sensitive information.
  2. An application that needs database access is installed on a computer that many people have access to.

Of course, one can hard-code connection strings into the source-code but compiled code, even obfuscated, can easily be decompiled. In addition, changing the connection string can be a hell because application must be recompiled and reinstalled.

The Solution

In this article, I will present three solutions to the problem stated above. I will present a short version of the first two solutions and will present a detailed version of the third one. I will also attach the source code for the third solution.

The First Solution

Encrypt the password before the application is shipped and create a service in your database server that will intercept any login attempt and will decrypt the password. That is probably the most secure solution, but the problem is that this solution is not easy to implement.

The Second Solution

Use protected section mechanism (courtesy of .NET Framework).

static public void ProtectSection()
{
    // Get the current configuration file.
    System.Configuration.Configuration config =
    ConfigurationManager.OpenExeConfiguration(
    ConfigurationUserLevel.None);
    // Get the section.
    AppSettingsSection section = (AppSettingsSection)config.GetSection("appSettings");
    // Protect the section.
    section.SectionInformation.ProtectSection(
    "RsaProtectedConfigurationProvider");
    // Save the encrypted section.
    section.SectionInformation.ForceSave = true;
    config.Save(ConfigurationSaveMode.Full);
}

This approach can be compared to bringing home the entire orange tree, when you only need a bag of oranges because the entire section will be encrypted.
If that is what you want, here is a good article describing that approach.

The Third Solution (Preferred, By Me)

In this solution, only certain settings of a section are encrypted using DPAPI.
Unfortunately DPAPI is not a flawless solution:

DPAPI is a password-based data protection service. It requires a password to provide protection. The drawback, of course, is that all protection provided by DPAPI rests on the password provided. This is offset by DPAPI using proven cryptographic routines, specifically the strong Triple-DES algorithm, and strong keys, which we'll cover in more detail later. Because DPAPI is focused on providing protection for users and requires a password to provide this protection, it logically uses the user's logon password for protection.

Nevertheless, DPAPI offers a reasonably good protection for your sensitive setting.

It is worth noting that DPAPI security is machine specific, meaning that data encrypted on one machine cannot be decrypted on another machine.

Code Walkthrough

Settings to encrypt are specified in the <appSettings> section of the configuration file.

<add key="KeysToEncrypt" value="ValuableKey1,ValuableKey2" />

Where, value is a set of keys to encrypt.

Here are the settings we want to encrypt in this example:

<add key="ValuableKey1" value="Top Secret 1" />
<add key="ValuableKey2" value="Top Secret 2" />

Since DPAPI security is machine specific, we will need to encrypt the configuration file on the machine that it will run from (web-server, for web applications).

ConfigUtility.ConfigEncryptToFile();
ConfigUtility.ConfigDecryptToMemory();

ConfigEncryptToFile method encrypts keys specified in “KeysToEncrypt” and updates the configuration file:

public static void ConfigEncryptToFile()
{
    string encrypted = ConfigurationManager.AppSettings.Get("Encrypted");
    if (encrypted == null || !encrypted.Equals("True"))
    {
        string keysToEncrypt = ConfigurationManager.AppSettings.Get("KeysToEncrypt");
        if (keysToEncrypt != null && keysToEncrypt.Length > 0)
        {
            Configuration config = 
	       ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            AppSettingsSection appSettings = config.AppSettings;
            string[] keys = keysToEncrypt.Split(',');
            foreach (string key in keys)
            {
                KeyValueConfigurationElement kv = appSettings.Settings[key];
                if (kv != null)
                {
                    kv.Value = EncryptUtility.EncryptString
			(EncryptUtility.ToSecureString(kv.Value));
                }
            }
            appSettings.Settings.Add("Encrypted", "True");
            config.Save(ConfigurationSaveMode.Modified);
        }  
    }
} 

ConfigDecryptToMemory reloads the configuration file and decrypts the keys:

public static void ConfigDecryptToMemory()
{
    ConfigurationManager.RefreshSection("appSettings");
    string encrypted = ConfigurationManager.AppSettings.Get("Encrypted");
    if (encrypted != null && encrypted.Equals("True"))
    {
        string keysToDecrypt = ConfigurationManager.AppSettings.Get("KeysToEncrypt");
        string[] keys = keysToDecrypt.Split(',');
        foreach (string key in keys)
        {
            string value = ConfigurationManager.AppSettings.Get(key);
            value = EncryptUtility.ToInsecureString
			(EncryptUtility.DecryptString(value));
            ConfigurationManager.AppSettings.Set(key, value);
        }
    }
} 

It is important to note that if we are really paranoiac about security, it is better to decrypt encrypted keys only when we actually use them, and keep them as SecureStrings in memory.

It is also worth noting that EncryptUtility class contains entropy and security can further be improved by generating a pseudo-random “entropy”.

EncryptUtility methods were written by Jon Galloway.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Sei Flavius
Engineer @ Truckwiser
United States United States
Check my technical blog for more tips and articles @ http://seifeet.com

Comments and Discussions

 
QuestionKeep comments PinmemberMember 1035020613-Dec-13 3:51 
QuestionMy vote of 5 PinmemberBjörn Ranft4-Mar-12 4:32 
Great Explanation.5!
AnswerRe: My vote of 5 PinmemberAndrey Tabachnik28-Jun-12 12:35 
GeneralMy vote of 5 PinmemberFilip D'haene26-May-11 9:22 
GeneralRe: My vote of 5 PinmemberAndrey Tabachnik10-Sep-11 14:03 
GeneralMy vote of 5 PinmemberPatrick Kalkman14-Mar-11 21:36 
GeneralRe: My vote of 5 PinmemberAndrey Tabachnik23-Mar-11 21:06 
GeneralXDP Pinmemberdaves_0513-Mar-11 5:06 
GeneralRe: XDP PinmemberAndrey Tabachnik13-Mar-11 17:24 
GeneralMy vote of 5 Pinmembereasey8-Mar-11 2:22 
GeneralMy vote of 5 Pinmemberjawed.ace7-Mar-11 22:43 
GeneralRe: My vote of 5 PinmemberAndrey Tabachnik8-Mar-11 7:43 
GeneralUse Windows Authentication PinmemberReaboi Artur7-Mar-11 18:11 
GeneralRe: Use Windows Authentication PinmemberAndrey Tabachnik7-Mar-11 19:22 
GeneralRe: Use Windows Authentication PinmemberReaboi Artur13-Mar-11 4:58 
GeneralMy vote of 5 PinmemberDrABELL7-Mar-11 9:48 
GeneralRe: My vote of 5 PinmemberAndrey Tabachnik7-Mar-11 14:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140916.1 | Last Updated 8 Mar 2011
Article Copyright 2011 by Sei Flavius
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid