Click here to Skip to main content
15,867,308 members
Articles / Programming Languages / C# 4.0

Securing Configuration Files in ASP.NET

Rate me:
Please Sign up or sign in to vote.
4.87/5 (12 votes)
7 Mar 2011CPOL3 min read 43K   414   31   18
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:

XML
<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).

C#
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.

XML
<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:

XML
<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).

C#
ConfigUtility.ConfigEncryptToFile();
ConfigUtility.ConfigDecryptToMemory();

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

C#
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:

C#
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)


Written By
Engineer @ Curbsidr
United States United States
Check our technical blog for more tips and articles @ https://curbsidr.com/blog/

Comments and Discussions

 
Questionhow to query agiant database for a user? Pin
sueiyoung5-Mar-20 15:28
sueiyoung5-Mar-20 15:28 
QuestionKeep comments Pin
Member 1035020613-Dec-13 3:51
Member 1035020613-Dec-13 3:51 
QuestionMy vote of 5 Pin
El_Codero4-Mar-12 4:32
El_Codero4-Mar-12 4:32 
AnswerRe: My vote of 5 Pin
Sei Flavius28-Jun-12 12:35
Sei Flavius28-Jun-12 12:35 
GeneralMy vote of 5 Pin
Filip D'haene26-May-11 9:22
Filip D'haene26-May-11 9:22 
GeneralRe: My vote of 5 Pin
Sei Flavius10-Sep-11 14:03
Sei Flavius10-Sep-11 14:03 
Thank you
GeneralMy vote of 5 Pin
Patrick Kalkman14-Mar-11 21:36
Patrick Kalkman14-Mar-11 21:36 
GeneralRe: My vote of 5 Pin
Sei Flavius23-Mar-11 21:06
Sei Flavius23-Mar-11 21:06 
GeneralXDP Pin
daves_0513-Mar-11 5:06
daves_0513-Mar-11 5:06 
GeneralRe: XDP Pin
Sei Flavius13-Mar-11 17:24
Sei Flavius13-Mar-11 17:24 
GeneralMy vote of 5 Pin
easey8-Mar-11 2:22
easey8-Mar-11 2:22 
GeneralMy vote of 5 Pin
jawed.ace7-Mar-11 22:43
jawed.ace7-Mar-11 22:43 
GeneralRe: My vote of 5 Pin
Sei Flavius8-Mar-11 7:43
Sei Flavius8-Mar-11 7:43 
GeneralUse Windows Authentication Pin
Reaboi Artur7-Mar-11 18:11
Reaboi Artur7-Mar-11 18:11 
GeneralRe: Use Windows Authentication Pin
Sei Flavius7-Mar-11 19:22
Sei Flavius7-Mar-11 19:22 
GeneralRe: Use Windows Authentication Pin
Reaboi Artur13-Mar-11 4:58
Reaboi Artur13-Mar-11 4:58 
GeneralMy vote of 5 Pin
DrABELL7-Mar-11 9:48
DrABELL7-Mar-11 9:48 
GeneralRe: My vote of 5 Pin
Sei Flavius7-Mar-11 14:42
Sei Flavius7-Mar-11 14:42 

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

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