Email the article.
Article
Download the article
(by John Roberts for Blayd Software)
Note: this article relates to the .Net Framework version 2.0 and later (3.0, 3.5, 4.0 and 4.5), some of the classes and class members referenced in this article were not available in earlier framework versions.
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.
*.ini
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.
System.Configuration
System.Web.Configuration
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.
appSettings
ConfigurationManager.AppSettings
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.
Protected configuration is implemented in the .Net Framework (version 2.0 onward) 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 familiarize 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.
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. The .Net Framework (version 2.0 onward), 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.
System.Configuration.ProtectedConfigurationProvider
System.Configuration.Provider.ProviderBase
ProtectedConfigurationProvider
The protected configuration provider classes included in the .Net Framework are as follows.
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.
machine.config
app.config
web.config
RsaProtectedConfigurationProvider
DpapiProtectedConfigurationProvider
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.
name
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", while 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.
The machine.config definition of an RsaProtectedConfigurationProvider protected configuration provider instance is, typically, as follows.
<configProtectedData defaultProvider="RsaProtectedConfigurationProvider"> <providers> <add name="RsaProtectedConfigurationProvider" type="System.Configuration.RsaProtectedConfigurationProvider, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" description="Uses RsaCryptoServiceProvider to encrypt and decrypt" keyContainerName="NetFrameworkConfigurationKey" cspProviderName="" useMachineContainer="true" useOAEP="false" /> </providers> </configProtectedData>
Note
The sample configuration settings above are referencing the .Net Framework 4.0 version of the RsaProtectedConfigurationProvider class, however, you can change the version number to reference an earlier version of the framework. If you need to confirm the name of a provider class in order to create a declaration similar to the example above, you can retrieve the fully qualified name of a type using code similar to the following example.
Retrieving the fully qualified name of a type.
string qualifiedName = typeof(RsaProtectedConfigurationProvider).AssemblyQualifiedName;
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 its class or type name. All of the protected configuration provider instance definitions are grouped within a single providers element.
configProtectedData
defaultProvider
providers
The attributes for an RSA protected configuration provider definition are as follows.
true
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.
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.
The machine.config definition of a DpapiProtectedConfigurationProvider protected configuration provider instance is, typically, as follows.
<configProtectedData defaultProvider="RsaProtectedConfigurationProvider"> <providers> <add name="DataProtectionConfigurationProvider" type="System.Configuration.DpapiProtectedConfigurationProvider, System.Configuration, Version=4.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 its 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.
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.
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.
ProviderBase
System.Configuration.Provider
Initialize
Name
Description
Encrypt
XmlNode
OuterXml
Decrypt
InnerText
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 a 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.
NameValueCollection
type
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.
codeBase
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 its 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:
Aspnet_regiis.exe
%windows%\Microsoft.NET\Framework\versionNumber
You can use the Visual Studio 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 ASP.Net Command-Line 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 the download registration page....
To manually encrypt a configuration section using RSA encryption you will require, at least, read access to the relevant key container. Even if you are using the default .Net Framework key container i.e. the "NetFrameworkConfigurationKey" container you will need to run the command line tool with administrator privileges or from an account with read access to the container.
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.
To assess the impact that encryption can have on your configuration settings we have encrypted the appSettings section of a configuration file.
<configuration> <appSettings> <add key="SensitiveKey1" value="SensitiveValue1" /> <add key="SensitiveKey2" value="SensitiveValue2" /> <add key="SensitiveKey3" value="SensitiveValue3" /> <add key="SensitiveKey4" value="SensitiveValue4" /> </appSettings> </configuration>
<configuration> <appSettings configProtectionProvider="RsaProtectedConfigurationProvider"> <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns="http://www.w3.org/2001/04/xmlenc#"> <EncryptionMethod Algorithm="http://www.w3.org/2001/04/ xmlenc#tripledes-cbc" /> <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#"> <EncryptionMethod Algorithm="http://www.w3.org/2001/04/ xmlenc#rsa-1_5" /> <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> <KeyName>Rsa Key</KeyName> </KeyInfo> <CipherData> <CipherValue> QXNNzE1+Nugve6RLaLFUqBhMNPbnJEuomsy OiYo/B7lGi+BaNOrj08VGZqOGyvjucxyG5p WC/ZXgs9C83VZIaH8n/OGyirl59GNZ+HK7K 6188nxviNR0ZoljLXGI2Q+MkIDI55g9HpeW KwDNS8y9PlldPRJ0W3VUv9T6TiTNuYw= </CipherValue> </CipherData> </EncryptedKey> </KeyInfo> <CipherData> <CipherValue> oryMqG3Gx0i7R37lLwi6kVYHQRN5Cp80JqWZULe+Q D2OfLW9EOPIrWbAyZVUQSzcLOd3+5C45Qr+yUVuAL Z8pZraDHECoEGo9vu7GJzVNhynU/9XAvMkEV/msiX ckBuqJ25hkVAAp3/Q5Z285UODAAyLyJTt/L6TwMB/ cZ+5WL/AdLLU8UC7Xbt26aNogr5z9ju3bIpGrxk6j scBmuVoUm8JzXvJah9ah3RhypToMyWGOGm9DbxKNA 5ztMzypRiIFoh2i9Po8rQuOdRzjbQZT0bqf0/yEJp gQpbZDjly3lmLlgMGY0wCr0QiVFwYhwaIwMpHLS7M uY734AUyIrFw7aGHlHb/QiVIz5PzeffT22M= </CipherValue> </CipherData> </EncryptedData> </appSettings> </configuration>
As you can see, the structure of the RSA encrypted section is verbose and inflates the size of the configuration section considerably. Encrypting with the DPAPI protected configuration provider is, typically, more efficient in terms of data overhead but it is limited to encrypting and decrypting on the same machine.
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 friendly name of the encrypting protected configuration provider e.g. "RsaProtectedConfigurationProvider". You do not have to specify the friendly 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.
configProtectionProvider
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(); } } } }
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 your own 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.
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 - 2013