WEBINAR:
On-Demand
Application Security Testing: An Integral Part of DevOps
Encrypting Configuration Keys
The final feature of the class that I want to demonstrate is encryption of selected keys. A lot of configuration information is essential, so you might want to protect the
.config file by encrypting sensitive keys. The purpose is to prevent people from physically looking into the
Web.config file and gaining access information for, say, the database connection string. Instead, this information should only be available for editing through the application itself and, most likely, through password-protected access forms that require a valid log on.
One big thing missing from the .NET ConfigurationSettings class is the ability to write values back out to the .config file.
|
|
To add encryption, I use a simple support class called wwEncrypt that is provided with the source for this article. This class uses two-way DES encryption to encrypt and also decrypt specific values.
In order to implement this functionality, I added two private properties to the wwAppConfiguration base class:
private string EncryptFieldList = "";
private string EncryptKey = "";
EncryptFieldList is a comma-delimited list of fields that you want to have encrypted. The
EncryptKey is the Key used to encrypt and decrypt the fields as they are read from the configuration and out to disk in the
ReadKeysFromConfig/WriteKeysToConfig methods.
There's also a special Constructor and a SetEncryption() method used to set these fields. This Constructor looks like this:
public wwAppConfiguration(string EncryptFields,
string EncryptKey)
{
this.SetEncryption(this.EncryptFieldList,
EncryptKey);
this.ReadKeysFromConfig();
}
If you want more control, you can also create the object and call the
SetEncryption() method directly
WebStoreConfig Config = new WebStoreConfig(true);
Config.SetEncryption("ConnectionString,MailPassword",
"SuperSecret");
Config.SetConfigurationSection("MyApplication");
this.ReadKeysFromConfig();
Note the constructor call with a Boolean value parameter which stops the default loading of configuration settings until you explicitly call
ReadKeysFromConfig().
The
ReadKeysFromConfig method and the
WriteKeysToConfig method then add a couple of lines of code to handle the encryption and decryption as part of the member loops that go through each of the properties. Here's the relevant
Read code, which fires immediately after you retrieve the value from the
AppSettings section.
if (Value != "" && this.EncryptFieldList.IndexOf("," +
Fieldname + ",") > -1 )
Value = wwEncrypt.DecryptString(
Value,this.EncryptKey);
Here, you decrypt the string and store the decrypted value in the object. On the
Write end, the process is reversed. Immediately after reading the value from the property and converting it to a string, it is encrypted:
if (this.EncryptFieldList.IndexOf("," +
Field.Name.ToLower() + ",") > -1)
Value = wwEncrypt.EncryptString(
Value,this.EncryptKey);
With the right routines in place, this process is really easy. You can find the
EncryptString and
DecryptString methods in the wwEncrypt class in the source.
In order for you to enable this encryption for your own subclass, all you have to do is implement a custom constructor that calls back to the base class and passes the
EncryptFields and the
EncryptKey.
public WebStoreConfig() : base(false)
{
this.SetEncryption("
this.ReaadKeysFromConfig();
}
Of course, you can also just call the two-parameter constructor directly, but generally, I prefer to have this done all in one place and forget about it.
How Secure Is This?
Because the encryption relies on a key phrase to provide encryption, it is possible to hack the code and retrieve the password. It's recommended that you use something a little less obvious than
WebStoreAppPassword for your encryption key. Needless to say, the value of this key has to be stored somewhere and it's up to you to decide how to make the key secure.
Encryption occurs when keys are written out to the
.config and decryption occurs when keys are written back to the object. This means that the in-memory object has full, unencrypted access to the data in the configuration file. So while your application runs, the values are available. If your UI displays these values, it's highly recommended that you password protect any forms that let you access this data. On a Web Form, use Windows, Basic, or Forms Authentication to require a login before displaying or allowing edits of the data.
This solution is meant to be a prevention mechanism for
casual discovery by just browsing the configuration file, but it's obviously not bullet proof. Somebody hacking into the source can figure out how to get around the encryption pretty easily; using the classes in the assembly that actually accomplish this hacking task. Unless the architecture of the application is known though discovering the key or using the class to read, the data is not obvious and so deters casual snooping. The other half of this is your application: If you allow editing of configuration values, you also need to make sure you protect the pages of the application that make these settings available.
Configure It
Maintaining configuration information should be easy; I hope this Configuration class simplifies the process to the point that you use configuration and customization options frequently. Having this information always available, along with the help of IntelliSense, makes this a big improvement over the native functionality of the .NET ConfigurationSettings class. And remember: the more configurable your application, the more flexible it is.