Thursday, April 18, 2013

How to encrypt app settings in a web.config

In a web application I recently developed, I found the need to store credentials for a rather powerful service account in my web.config.  The reason being, I needed to authenticate as that service account user at times, and use normal user credentials at others.  I was able to use the service account details without issue, but incase we ever found the need to update the account name or password, I wanted to make this value part of the web.config, but also have the means to encrypt this value to shield it from prying eyes.  Fortunately, using some web.config transforms and the aspnet_regiis –pef command option, this isn’t all too difficult, and we can have a perfectly normal web.config, but encrypt just one section of the web.config to hide sensitive data.

Step 1, Create a new web.config section

In your web.config, within the configuration\configSections area, add the following XML:

<section name="secureAppSettings" type="System.Configuration.NameValueSectionHandler, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

This XML will allow us to create a new section called secureAppSettings within our config.  You can call this whatever you want of course, but me… I like secureAppSettings.

Still within your config file, after your <appSettings> section, create a new section called secureAppSettings, and within this section add your key\value pairs, like so:

<secureAppSettings>
  <add key="testkey" value="This is a value in secureAppSettings testkey"/>
</secureAppSettings>

Step 2, reference your value’s in your code

Now that you created your values, you reference them in your application *almost* like normal.  Rather than referencing your AppSettings object of the ConfigurationManager class, you need to reference the “secureAppSettings” section instead.  This is simple.. but a minor change nonetheless.  So, find where your code is looking to reference our new secure values and reference the secureAppSettings key like follows:

Dim myVal as String = ConfigurationManager.GetSection("secureAppSettings")("testkey").ToString

Do you see the difference?  Here, we need to use the “GetSection” method, and then specify our “secureAppSettings” section.  Then, we reference our “testkey” value.  As I said, it’s a minor change.  Also take note, we do not need to do anything different to worry about the encryption\decryption of the web.config value, as the .NET Framework will handle that for us.  We simply need to reference the value, the .NET Framework will handle the rest.

Step 3, Encrypt Your Config Section

Here’s the fun part.  Publish your application, so you have a full config file.  (Personally, I like to publish to a local directory on my PC so I can push all files to my staging\production server’s manually when possible).  Once you publish the application, navigate to the publish directory and take a peek at the web.config.  How does it look?  Like normal, right?  Take this file and copy it to your web server, then remote into your web server and open a command prompt (run as admin just to be safe).  The encrypted values are generated based on the server’s machine key, so executing these command’s on a PC that isn’t your web server could cause unintended results.

Once within a cmd prompt, execute the following 2 command’s

1.) cd C:\Windows\Microsoft.NET\Framework64\v4.0.30319

2.) aspnet_regiis -pef "secureAppSettings" "E:\YourPhysicalPathToTheFileLocation" -prov DataProtectionConfigurationProvider

For your physical path to the file location in the 2nd command, you do not need to specify the file name, simply the directory it resides in.  So it would be “E:\mydir\mysubdir”, NOT “E:\mydir\mysubdir\web.config”. Once you complete both commands, take a look at your config now.  You should see something similar to the following:

<secureAppSettings configProtectionProvider="DataProtectionConfigurationProvider">
  <EncryptedData>
    <CipherData>
      <CipherValue>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAxFAcBHLMb0uk5ES0SYgO2AQAAAACAAAAAAA………………………..2fZwOKP8VFg7OW2eMYFnq86TbUhB92EOQk0DhPqxDaA0pnp7MwRq2YR5CjmVAOFAAAAAxzUbeL1Fuij0DFEe0Cb7KEa92/</CipherValue>
    </CipherData>
  </EncryptedData>
</secureAppSettings>

Check it out!  Now, your secureAppSettings config values are encrypted!  As stated earlier, there’s no need to reference these values any differently in your code, other than specifying the secureAppSettings section.

Step 4, Merging these values back within your code

As I stated earlier, I needed to encrypt a username and password, just incase the value needs to change later on.  So in my scenario, I only need to document this process and generate my encrypted values once.  Then, if I ever need to publish a new build, I can still promote the same config values, and only worry about updating these username\password values if they ever change.  To handle this, I just placed my secureAppSettings in a web.config transform.  To do so, within Visual Studio, open your Web.Release.config transform file.  In the appropriate section (for me, this was below connectionStrings and above system.web), place your encrypted values using xdt transform notation:

<secureAppSettings configProtectionProvider="DataProtectionConfigurationProvider" xdt:Transform="SetAttributes">
<add xdt:Transform="RemoveAll" />

  <EncryptedData xdt:Transform="Insert">
    <CipherData>
      <CipherValue>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAxFAcBHLMb0uk5ES0SYgO2AQAAAACAAAAAAA………………………..2fZwOKP8VFg7OW2eMYFnq86TbUhB92EOQk0DhPqxDaA0pnp7MwRq2YR5CjmVAOFAAAAAxzUbeL1Fuij0DFEe0Cb7KEa92/</CipherValue>
    </CipherData>
  </EncryptedData>
</secureAppSettings>

The code above does a few things.

1. The SetAttributes on the secureAppSettings node causes the transform to add the configProtectionProvider attribute.

2. The RemoveAll transform removes any non-encrypted key\value pairs you may have in your web.config prior to performing a publish.  This means that your web.config during local debugging can still have your clear text key\value pairs, but they’ll get removed when you perform your publish.

3. the Insert transform will cause the EncryptedData, CipherData and CipherValue nodes to copy into your transform.

Step 4b – Updating your encrypted values

Should you have the need to recreate a clear text version of your web.config again, so you can update your values and re-encrypt them, just create a new publish profile within Visual Studio that publishes to a directory, but does NOT use your web.release.config transform.  This way, you can publish your config to a local directory and repeat the steps listed above.

Hope this helps!

No comments:

Post a Comment