Protected Configuration
(by John Roberts for Blayd Software)
Introduction
A significant number of the applications that we develop use variable data values
to set their initial state e.g. Window location, font-size, colour, etc. or to specify
the values of a resource required at runtime e.g. path, file name, database name,
etc. Even if the number of possible values for a particular settings is limited,
hard coding them into an application has never been an ideal solution as it limits
the flexibility of the application and requires a re-compile to update an existing
value or to add a new value. Before the arrival of the .Net Framework we could use
initialization (ini) files and/or the registry to store configuration settings and
the Windows API to load them or we had to implement our own configuration system.
We can, of course, still use any of these options, however the .Net Framework includes
a built-in, XML based, configuration system that is the recommended solution for
configuring .Net Framework applications.
The .Net Framework configuration system is extensive and extensible and includes
functionality that developers can use to configure their applications and functionality
that system administrators can use to configure assemblies and the .Net Framework
itself. The classes or types relating to application configuration are contained
in the System.Configuration namespace and there are additional types, relating to
ASP.Net configuration, contained in the System.Web.Configuration namespace.
Dynamically configuring applications that target the .Net Framework is really easy
and in most cases just requires a configuration file, in the application's working
directory, with an appSettings section containing the required values, each one
identified by a unique key. Each individual configuration setting can then be accessed
in the application's code by using the ConfigurationManager.AppSettings property
and the relevant unique key.
Microsoft extended the .Net Framework configuration system in version 2.0 of the
framework to include functionality to protect or encrypt individual configuration
sections in a configuration file. Configuration files often have to be used to store
sensitive data, for example, you may have to store user names, passwords, database
connection strings and many other types of sensitive data in a configuration file
for a Windows Forms or an ASP.Net Web Application. Protected configuration can be
used to improve the security of your application by making it difficult for an attacker
to gain access to the data even if they manage to gain access to the configuration
file.
Provider Model
Protected configuration is implemented in version 2.0 of the .Net Framework using
the Provider Model. The Provider Model is a factory like design pattern that allows
a developer to define a concrete provider class, derived from a known provider (abstract)
base class, in a configuration file. The .Net Framework uses the configuration file
definition to create an instance of the relevant provider class at runtime. The
provider instance is then called upon to provide the relevant service, in the case
of protected configuration, to encrypt and decrypt a configuration file section.
It is beyond the scope of this article to delve too deeply into the Provider Model
but we recommend that you familiarise yourself with this design pattern as it is
used a lot in the .Net Framework and may be of use in your own applications or systems.
The following two articles are our recommended starting point:
Protected Configuration Providers
A protected configuration provider is a class that derives from the System.Configuration.ProtectedConfigurationProvider
class. This is an abstract base class that derives from the System.Configuration.Provider.ProviderBase
class and therefore inherits the (very) basic functionality of a provider. Version
2.0 of the .Net Framework, includes two, ready to run, protected configuration providers
that can be used to encrypt and decrypt configuration settings and you can also
develop your own, custom, provider by extending the ProtectedConfigurationProvider
class.
The protected configuration provider classes included in the .Net Framework are
as follows:
- RsaProtectedConfigurationProvider
- This protected configuration provider uses the RSA algorithm to encrypt and decrypt
configuration settings. Typically, this provider is specified as the default protected
configuration provider.
- DpapiProtectedConfigurationProvider
- This protected configuration provider uses the Windows Data Protection API to encrypt
and decrypt configuration settings.
As noted, in the Provider Model section above, the .Net Framework runtime uses the
data specified in a configuration file to identify and initialize the required instance
of a protected configuration provider. A protected configuration provider instance
can be specified in the machine.config, app.config or web.config file. In a typical
.Net Framework installation the attributes or properties for instances of the RsaProtectedConfigurationProvider
and DpapiProtectedConfigurationProvider classes are specified in the machine.config
file. Therefore, by default, they can both be used to encrypt and decrypt your configuration
settings without requiring further definition in your application's configuration
file, providing you are happy to use the provider's machine.config specified attributes.
If you want to use different attribute or property values for either of these two
protected configuration providers, for example, you may want to specify a different
key container for the RSA provider or specify a key entropy for the DPAPI provider,
you will have to override the machine.config file settings in your application's
configuration file by adding your own protected configuration provider instance
settings.
Specifying the attributes of a protected configuration provider in the machine.config
file or in an app.config or web.config file can be thought of as defining an instance
of the provider. You can, for example, have several definitions or instances of
the RsaProtectedConfigurationProvider, each with its own set of, unique, attributes.
Protected configuration providers are identified by a unique friendly name that
is specified in the name attribute value. The .Net Framework uses the provider's
friendly name to identify, create and initialize an instance of the provider at
runtime.
A provider's friendly name is not necessarily its class or type name, it can be
any value. It is interesting or perhaps confusing to note that the RsaProtectedConfigurationProvider
instance defined in the machine.config file is named 'RsaProtectedConfigurationProvider',
whilst the DpapiProtectedConfigurationProvider instance defined in the machine.config file is named
'DataProtectionConfigurationProvider'. The important thing to remember
is that if you define your own protected configuration provider instance you should
give it a name that is meaningful and relevant to the provider's use.
RSA Protected Configuration Provider
The machine.config definition of an RsaProtectedConfigurationProvider protected
configuration provider instance is, typically, as follows:
RSA protected configuration provider attributes
<configProtectedData defaultProvider="RsaProtectedConfigurationProvider">
<providers>
<add name="RsaProtectedConfigurationProvider"
type="System.Configuration.RsaProtectedConfigurationProvider,
System.Configuration, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a"
description="Uses RsaCryptoServiceProvider to encrypt and decrypt"
keyContainerName="NetFrameworkConfigurationKey"
cspProviderName=""
useMachineContainer="true"
useOAEP="false" />
</providers>
</configProtectedData>
There is only one configProtectedData section element and in a typical installation
the 'RsaProtectedConfigurationProvider' is specified as the default protected configuration
provider. You should note that the value of the defaultProvider and name attributes
refer to the friendly name of the provider not it's class or type name. All of the
protected configuration provider instance definitions are grouped within a single
providers element.
The attributes for an RSA protected configuration provider definition are as follows:
- name
-
The friendly name of the provider. This is the value that you would specify as the
protectionProvider parameter value if you are explicitly using the provider to encrypt
or decrypt a configuration section in your code.
- type
-
The assembly qualified type name of the protected configuration provider. The .Net
Framework must be able to locate the provider in order to automatically decrypt
an encrypted configuration section when it is loaded into memory.
- description
- The protected configuration provider description.
- keyContainerName
-
The name of the RSA key container to be used when encrypting and decrypting configuration
section data. The 'NetFrameworkConfigurationKey' RSA key container is created when
the .Net Framework is installed. Although all machines containing an installation
of the .Net Framework will, typically, have an RSA key container named 'NetFrameworkConfigurationKey'
each will have a different, generated, key pair. Therefore you cannot encypt on
one machine using the 'NetFrameworkConfigurationKey' key container and decrypt on
another machine using the 'NetFrameworkConfigurationKey' key container, as the keys
will, typically, be different.
- cspProviderName
- The name of the Windows cryptography API (crypto API) cryptographic service provider
(CSP).
- useMachineContainer
-
True if using a machine-level RSA key container, False if using a user-level RSA
key container. If you are intending to encrypt the configuration data on one machine
and have it decrypted on another or several other machines you should use a machine-level
RSA key container.
- useOAEP
-
True if using Optimal Asymmetric Encryption Padding (OAEP) when encrypting and decrypting,
otherwise False.
The RSA protected configuration provider can be used to encrypt configuration section
data on one machine and decrypt it on another machine and is therefore an ideal
candidate for protecting web.config file sections in, for example, a web farm installation.
To use an instance of the RSA protected configuration protector to encrypt on one
machine and decrypt on another or several other machines you will have to take the
following steps:
- Create a machine-level RSA key container on the encrypting machine.
- Define the attributes of an instance of the RSA protected configuration provider,
that uses the RSA key container created in the previous step, in the
web.config
file.
- Encrypt the relevant
web.config section(s) using the RSA protected configuration
provider instance defined in the previous step.
- Export both the public and private keys from the RSA key container created in
step 1. The public key is used to encrypt configuration data and the private key
is required to decrypt it.
- On the decrypting machine or machines, import both the public and private keys,
exported in the previous step, into an RSA key container with the same name as the
container on the encrypting machine.
- On the decrypting machine or machines, grant read access to the newly create
RSA key container to the Windows identity of the relevant web application.
You can find the Windows or process identity under which your web application is
running, assuming that you are using anonymous authentication, by temporarily adding
the following code to a page load event and outputting the result to the Response
stream:
System.Security.Principal.WindowsIdentity.GetCurrent().Name
The value of this property is the account name under which your web application
is running. This account needs read access to the relevant RSA key container in
order for the .Net Framework to use the relevant protected configuration provider
to automatically decrypt configuration section data as it is loaded.
DPAPI Protected Configuration Provider
The machine.config definition of a DpapiProtectedConfigurationProvider protected
configuration provider instance is, typically, as follows:
DPAPI protected configuration provider attributes
<configProtectedData defaultProvider="RsaProtectedConfigurationProvider">
<providers>
<add name="DataProtectionConfigurationProvider"
type="System.Configuration.DpapiProtectedConfigurationProvider,
System.Configuration, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a"
description="Uses CryptProtectData and CryptUnProtectData
Windows APIs to encrypt and decrypt"
useMachineProtection="true"
keyEntropy="" />
</providers>
</configProtectedData>
There is only one configProtectedData section element and in a typical installation
the 'RsaProtectedConfigurationProvider' is specified as the default protected configuration
provider. You should note that the value of the name attribute refers to the friendly
name of the provider not it's class or type name. All of the protected configuration
provider instance definitions are grouped within a single providers element.
The attributes for an DPAPI protected configuration provider definition are as follows:
- name
-
The friendly name of the provider. This is the value that you would specify as the
protectionProvider parameter value if you are explicitly using the provider to encrypt
or decrypt a configuration section in your code.
- type
-
The assembly qualified type name of the protected configuration provider. The .Net
Framework must be able to locate the provider in order to automatically decrypt
an encrypted configuration section when it is loaded into memory.
- description
- The protected configuration provider description.
- useMachineProtection
True to use machine-level DPAPI protection, False to use user-level DPAPI protection.
- keyEntropy
-
Only relevant when using machine-level protection. An application specific value,
that can be thought of as a password, to use with the encryption key to protect
against other applications on the same machine decrypting information.
The DPAPI protected configuration provider cannot be used to encrypt configuration
data on one machine and decrypt it on another machine, the Data Protection API is
machine specific. However, if this is not a problem for your implementation, this
provider is probably the easiest to use because it has fewer configuration options.
Custom Protected Configuration Provider
The Provider Model Design Pattern used by the .Net Framework protected configuration
provider implementation allows developers to define a specific protected configuration
provider instance that is to be used by the framework to encrypt and decrypt configuration
data. Therefore, if the neither of the two protected configuration providers supplied
in the .Net Framework meet your requirements you can develop your own custom provider,
specify the attributes for your provider in a configuration file and have the .Net
Framework use your provider to encrypt and decrypt configuration section data.
Your custom protected configuration provider class must inherit from the ProtectedConfigurationProvider
abstract base class contained in the System.Configuration namespace. The ProtectedConfigurationProvider
class inherits from the ProviderBase abstract base class contained in the System.Configuration.Provider
namespace, therefore, there are several abstract members that your provider class
must implement and several virtual members that your provider class should override.
The relevant members are as follows:
- Initialize
-
This is a virtual method of the
ProviderBase class and should be overridden to setup
your provider. The base class implementation tracks the number of calls to Initialize
and only allows a single call, therefore, if you only want a single instance of
your provider to exist, your code should call the base class implementation. The
provider's friendly name is passed to the Initialize method together with a collection
of name value pairs representing the provider's attributes from the configuration
file. If your implementation does not call the base class version of Initialize
you should capture the friendly name and possibly the provider's description and
override the Name and possibly the Description properties.
- Encrypt
-
This is an abstract method of the
ProtectedConfigurationProvider class and must
be overridden in your provider. The Encrypt method is passed an XmlNode instance
representing the configuration data to encrypt. Your code should encrypt the data
contained in the node i.e. the OuterXml property value, wrap the encrypted data
in an element named 'EncryptedData' and return the resulting node.
- Decrypt
-
This is an abstract method of the
ProtectedConfigurationProvider class and must
be overridden in your provider. The Decrypt method is passed an XmlNode instance
representing the data to decrypt. Your code should decrypt the data contained in
the node i.e. the InnerText property value and return the resulting node.
It is worth noting that although the two main methods are named Encrypt and Decrypt
it is up to you to define exactly what these methods do. The Encrypt method does
not have to encrypt the configuration data, it may, for example, store the configuration
data in a location that is more secure than the configuration file and then just
place an opaque marker in the configuration file indicating, in some way, that the
actual configuration data is external. You may be able to come up with other, better,
ideas, our point is that you have the freedom to protect your configuration data
in whatever way you choose.
The Initialize method is passed a NameValueCollection containing the configuration
attributes of the custom provider. Your custom provider must have, at least a name
and type attribute, as these values are required by the .Net Framework to locate
and load your provider. In addition to the two required attributes you can add your
own attributes to the provider's configuration settings and retrieve the value of
these attributes in your provider's Initialize method. You should, note, however,
that the provider's attributes are in clear text in the configuration file, so if
the file is accessible then so are your provider's attributes.
When you have completed your custom protected configuration provider class you need
to ensure that the .Net Framework can find it when it needs to encrypt and decrypt
the relevant configuration section data. There are several options available for
deploying a custom protected configuration provider and they depend on how you are
going to encrypt the configuration data and the type and number of applications
that are going to use the provider.
Some of the options available are as follows:
- Add the provider class to your application's assembly.
-
If you are intending to encrypt and decrypt configuration section data explicitly
from code and your provider is only going to be used by one application this solution
should be fine. However, if you are going to use a tool (see the Encrypting and
Decrypting Configuration Data section below) to manually encrypt the data and have
the .Net Framework automatically decrypt the data as it is loaded, this solution
can be problematic. To manually encrypt the data, your application's assembly and
the encrypting tool will, typically, have to be in the same directory or you will
have to add a
codeBase element to the encrypting tool's configuration file pointing
to your application's assembly. Automatically decrypting the data should be fine
as the .Net Framework will look in your application's assembly for the provider.
If you are intending to use the provider from more than one application, this solution
is not really suitable.
- Place the provider class in it's own assembly.
-
Compile the provider class in it's own assembly and place one copy of the assembly
in the same directory as the tool used to manually encrypt the configuration data
and another copy in your application's directory. Using this solution you will be
able to use a tool to manually encrypt the configuration data and have the .Net
Framework automatically decrypt the configuration data at runtime. If you are going
to use the provider from more than one application then each application will required
a copy of the provider's assembly in its directory.
- Add the provider class to the Global Assembly Cache.
-
Compile your custom protected configuration provider in it's own assembly with a
strong name and place the assembly in the global assembly cache (GAC). This is probably
the easiest way to make your provider available to multiple processes on the same
machine.
Encrypting and Decrypting Configuration Data
If you have defined the required protected configuration provider in the machine.config
or in your app.config or web.config file, the .Net Framework will automatically
decrypt any configuration section data encrypted by the provider at runtime. However,
this does mean that you will have to manually encrypt the configuration section
data before deploying your application and it's configuration file.
The .Net Framework includes a command line tool, named Aspnet_regiis.exe, that can
be used to encrypt and decrypt configuration section data and also to manage RSA
key containers for the RsaProtectedConfigurationProvider class. The Aspnet_regiis.exe
command line tool is located in the following directory:
%windows%\Microsoft.NET\Framework\versionNumber
You can use the .Net Framework command prompt, which has the relevant environment
variables setup, to make use of the Aspnet_regiis.exe tool to encrypt your configuration
section data. Full details of the various switches and parameters for Aspnet_regiis.exe
can be found in the .Net Framework documentation under the .Net Framework Tools
section.
If you are not a fan of command line applications, Blayd Software supply a developer
tool named Configuration Protector that provides a graphical user interface that
enables configuration sections to be encrypted and decrypted using a point and click
technique that reduces typing and therefore mistakes and speeds up the whole process.
In addition to providing a simple and intuitive user interface for encrypting and
decrypting configuration file sections the Configuration Protector also provides
a graphical user interface for managing RSA key containers and their keys. You can download
a free evaluation version of Configuration Protector from www.blayd.co.uk.
When using protected configuration to protect your sensitive configuration section
data you should note that the configuration data is in encrypted form in the configuration
file but it is decrypted as it is loaded into memory, therefore, if an attacker
has access to the memory of your application they, potentially, have access to the
sensitive configuration data.
Encrypting and Decrypting Configuration Data in Code
As explained in the previous section the .Net Framework will automatically decrypt
configuration section data as it is loaded into memory if the relevant provider
details are defined in the machine.config or your app.config or web.config file.
You can also explicitly encrypt and decrypt configuration section data in your application
code if required. The following code examples demonstrate how to encrypt and decrypt
a configuration section in a web.config file. The examples are private helper methods
of a web page class and should be called with the name of the section to encrypt
or decrypt e.g. 'appSettings' and the name of the encrypting protected configuration
provider e.g. 'RsaProtectedConfigurationProvider'. You do not have to specify the
name of the protected configuration provider when decrypting a configuration section
because the .Net Framework can retrieve the provider name from the encrypted section's
configProtectionProvider attribute.
Encrypting a configuration section
private void ProtectSection(string sectionName, string providerName)
{
Configuration config =
WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
if (config != null)
{
ConfigurationSection section = config.GetSection(sectionName);
if (section != null)
{
SectionInformation sectionInfo = section.SectionInformation;
if ((!sectionInfo.IsProtected) && (!sectionInfo.IsLocked))
{
sectionInfo.ProtectSection(providerName);
sectionInfo.ForceSave = true;
config.Save();
}
}
}
}
Decrypting a configuration section
private void UnProtectSection(string sectionName)
{
Configuration config =
WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
if (config != null)
{
ConfigurationSection section = config.GetSection(sectionName);
if (section != null)
{
SectionInformation sectionInfo = section.SectionInformation;
if ((sectionInfo.IsProtected) && (!sectionInfo.IsLocked))
{
sectionInfo.UnprotectSection();
sectionInfo.ForceSave = true;
config.Save();
}
}
}
}
It may at first seem like a tempting proposition to encrypt and decrypt your configuration
section data from code. However, you should note that in the examples above the
Windows identity under which the web application is running requires read access
to the RSA key container and write access to the configuration file to perform both
the encryption and decryption. It may be possible to grant these permissions in
your environment but most web applications will be using anonymous authentication
and running in a partial trust environment and will not, typically, have the required
permissions.
Conclusion
Encrypting sensitive data in a configuration file will improve the security of your
application by making it difficult for an attacker to gain access to the data even
if they manage to gain access to the configuration file. The addition of protected
configuration providers to the .Net Framework configuration system has made the
task of protecting configuration settings a lot easier for developers. The flexibility
and extensibility of the system should make it possible to protect configuration
data in most applications or systems, although, in some situations you will still
have some development work to do.
Copyright ©Blayd Software Limited 2007-2010. All rights reserved.