Encrypting Configuration File Sections

Encrypting Configuration File Sections

There is a good chance that at some point, you'll need to store sensitive information in an ASP.NET configuration file. A common example of a situation like that is the need to store the user name and password in a connection string required to connect to a database. IIS and ASP.NET make it very difficult for a casual user to read .config files, but users who have read access on the server may be able to read the sensitive information. So, to fix that issue, you'll want to encrypt the sensitive configuration information. Encrypting techniques have been around for a long time in ASP.NET, but I still find that a number of developers are unaware of them.

It's very easy to encrypt a section of a configuration file programmatically using the protected configuration features in ASP.NET. The ProtectedConfigurationProvider class in the System.Configuration namespace is the base class for all protected configuration providers. Use a protected configuration provider for encrypting and decrypting sections of a web.config file, such as the connectionStrings section. What's nice about this method  is that once you protect a section with encryption, you don’t need to decrypt it before it can be read; when your application needs to access the encrypted data, the .NET Framework will automatically decrypt the data for you.

The .NET Framework includes two protected configuration providers that you can use to encrypt sections of a configuration file:

  • The DPAPIProtectedConfigurationProvider uses the Windows Data Protection API (DPAPI) to encrypt and decrypt configuration sections. The DPAPIProtectedConfigurationProvider uses a machine-specific key that can only be used for configuration files located on the same computer. This function is useful for anonymous services, but provides less scalability than the RSAProtectedConfigurationProvider.
  • The RSAProtectedConfigurationProvider uses the RSACryptoServiceProvider to encrypt and decrypt configuration sections. This provider uses RSA public key encryption, which is required for encrypting and decrypting configuration files that will be used on multiple computers. You'll want to use this provider if you're going to need to move your web application to another machine, like you would in a server farm.

These providers are registered in the configProtectedData section of the machine.config file, and you can find the file in a default .NET installation at:

C:\Windows\Microsoft.NET\Framework64\v<version>\Config

Deep within the bowels of this file, you’ll find the configProtectedData section, which looks like the following (some of the data was removed to save space):

<configProtectedData defaultProvider="RsaProtectedConfigurationProvider">
   <providers>
       <add name="RsaProtectedConfigurationProvider" 
           type="..." description="Uses RsaCryptoServiceProvider to encrypt and decrypt"
           keyContainerName="NetFrameworkConfigurationKey"
           cspProviderName="" useMachineContainer="true" useOAEP="false"/>
       <add name="DataProtectionConfigurationProvider" 
           type="..."
           description="Uses CryptProtectData and CryptUnProtectData Windows APIs to encrypt and decrypt"
           useMachineProtection="true" keyEntropy=""/>
   </providers>
</configProtectedData>

Note that the DPAPIProtectedConfigurationProvider is registered as DataProtectionConfigurationProvider. The latter name is how you'll need to reference the encryption provider in your application.

Encrypting the connectionStrings Section in web.config

The connectionStrings section is a good candidate for encryption since it often contains sensitive information, such as the user name and password for a database, that could be used to mount an attack on your server. Although no one can browse to the web.config file through IIS or ASP.NET, anyone who has read permissions on the file share can simply open the file with a text editor.

The ToggleEncryption method, implemented here as an action method in an MVC application, toggles encryption for the connectionStrings section. It opens the connectionStrings section and checks whether it is already encrypted. If the section is not already encrypted, ToggleEncryption uses the SectionInformation.ProtectSection method to encrypt it, and when needed, uses the SectionInformation.UnprotectSection to decrypt the section. ToggleEncryption then creates a message about the state of encryption, and returns a null for the view model for the ConfigEncryption view.

public ActionResult ToggleEncryption()
{
    // Open the Web.config file.
    Configuration config = WebConfigurationManager.OpenWebConfiguration("~");

    // Get the connectionStrings section.
    ConnectionStringsSection section = (ConnectionStringsSection)config.GetSection("connectionStrings");

    // Toggle encryption.
    if (section.SectionInformation.IsProtected)
    {
        section.SectionInformation.UnprotectSection();
    }
    else
    {
        section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
    }

    // Save changes to the Web.config file.
    config.Save();

    ViewBag.Message = String.Format("IsProtected = {0}", section.SectionInformation.IsProtected);
    return View("ConfigEncryption", null);
}

This code uses the DataProtectionConfigurationProvider, which uses a machine-specific key for encrypting and decrypting configuration sections. This code is all you need if your site is running on a single server and you don't need to protect the data from other applications running on that server.

If you look at the web.config file after encrypting the connectionStrings section, you'll see that the raw connection strings were removed and some new settings were added, including the configProtectionProvider name as registered in machine.config. The <CipherData> element under <EncryptedData> contains the cipher text that represents the actual connection strings. The contents of CipherValue is a rather long string of gobbledygook, so I’ve removed it from the code.

<connectionStrings configProtectionProvider="DataProtectionConfigurationProvider">
   <EncryptedData>
       <CipherData>
           <CipherValue>...</CipherValue>
       </CipherData>
   </EncryptedData>
</connectionStrings>

You don’t need to write any additional code to encrypt external configuration files, so if you could move the entire connectionStrings section into a configuration file fragment called connections.config in the same folder as web.config, then you could modify the web.config file so that it points to the connections.config file:

<connectionStrings configSource=“connections.config” />

If you then encrypted the connectionStrings section, the connectionStrings section in the connections.config file would be encrypted, not the connectionStrings section in the web.config file that points to it.

When using the DataProtectionConfigurationProvider, Windows stores the encryption keys by default at the machine level. However, it is possible to store different keys for different user accounts. This option is useful if you're running multiple applications on a single server and don't want the applications to share a common key, such as in a hosting environment.

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish