Tuesday, February 03, 2009

ASP.Net – Exportable Encryption of web.config (server farms)

Alternate title for this post: Encrypting web.config for IIS server farms.

ASP.Net in version 2.0 of the .Net framework introduced the ability to encrypt configuration information using “Protected Configuration Providers”. ASPNET_IISREG.exe (ASP.Net IIS Registration Tool) is used to encrypt web.config files from the command line. (To do it programmatically – look at the System.Configuration namespace as well as this example: http://davidhayden.com/blog/dave/archive/2005/11/17/2572.aspx)

For more information check out MSDN documentation for Protected Configuration.

Examples abound on the Internet on how to encrypt web.config files. Almost all of these examples expect that you have a web-site setup on the computer where you wish to encrypt the web.config file. Instead I wanted a series of steps that would allow me to encrypt the web.config files on my development computer and then push it out to the test/production machines. And this post documents the steps to do just that. Such a procedure is also helpful when deploying your web-app to a server farm environment – where you cannot depend on a machine specific key for the encryption and decryption of the web.config contents.

1. Create RSA key container (Development machine).

aspnet_regiis -pc "testRSAKeyContainer" -exp
-pc: creates the key pair named “testRSAKeyContainer” and installs it for all users -exp: makes the key pair exportable 2. Export the RSA key container (Development machine).
aspnet_regiis -px "testRSAKeyContainer" "c:\keys.xml" -pri
-px: exports the key container “testRSAKeyContainer” to the location “c:\keys.xml” -pri: ensures that both private and public keys get exported 3. Prepare the web.config file for encryption (Development machine). Add the following code to the web.config file as a child of the <configuration> node (I prefer to do this before the ending configuration tag, as it looks cleaners).
<configProtectedData>
      <providers>
          <add name="SampleProvider" type="System.Configuration.RsaProtectedConfigurationProvider,
          System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a,
          processorArchitecture=MSIL"
          keyContainerName="testRSAKeyContainer"
          useMachineContainer="true"/>
      </providers>
</configProtectedData>
The important parts that need to be configured by you are underlined. name: This is the name for the configuration provider that you are creating in this section. keyContainerName: This is the name of the key container that you created in step 1 and exported in step 2. The <configProtectedData> section is used by ASPNET_IISREG.exe to determine how the web.config file will be encrypted.

4. Encrypt the web.config file (Development machine).

First, make a backup of the web.config file! Typically there are 2 sections that will be encrypted for most applications: connectionStrings and appSettings. If there are other sections that need to be encrypted, then make a note of those names. (The web.config is encrypted one section at a time, which is why you will require a list of sections that need to be encrypted).

If you need to encrypt the connectionStrings section, run the following command:

aspnet_regiis -pef "connectionStrings" "c:\webAppPhysicalLocation" -prov "SampleProvider"
-pef: encrypt section connectionStrings in web.config located at “c:\webAppPhysicalLocation” -prov: name of configuration provider specified in web.config file that will be used to encrypt the section. Specified as the name in step 3. Similarly, if you need to encrypt the appSettings section, run the following command:
aspnet_regiis -pef "appSettings" "c:\webAppPhysicalLocation" -prov "SampleProvider"

The following steps will be performed on each machine where your web-app will be deployed.

6. Import the RSA Key container into the machine. (Deployment machine) Copy the “keys.xml” file to the machine where the app needs to run. Run the following command to import the keys:

aspnet_regiis -pi "testRSAKeyContainer" "keys.xml" -exp

-pi: imports the keys in keys.xml for all users on the machine and names it “testRSAKeyContainer”. (Just to be on the safe side, be sure to use the same case for the name that was used to create the container in step 1 – it might be case-sensitive). -exp: imports it such that the key container is exportable. (important to be able to decrypt the web.config file)

note: In a server farm environment, you will import the key container into each machine that participates in the server farm.

7. Deploy the encrypted web.config file (Deployment machine)

Copy the encrypted web.config file from step 4 to the machine where the web-app is going to run. Run the application and test to make sure that you are able to decrypt the web.config file.

note: In case your application fails to start up with a configuration error, see step (3)’s note above.

Important Note: In some environments you will have to give the account that runs the web-app (typically ASPNET) permission to access the key container. This is done with the following command:

aspnet_regiis -pa testRSAKeyContainer ASPNET


Notes: 1. To delete a key container that has been installed to a machine, use the following command:

aspnet_regiis -pz "testRSAKeyContainer"

2. To test decryption: Decryption of a protected web.config file occurs on the fly. The easiest way to test it is to create an aspx file with the following text and run it from within a browser. Expects an AppSettings section with a key value pair for SecretValue1 and a ConnectionStrings section with a connection string named MyAppConnString.

<%@ Page Language="C#" %>
<%
  Response.Write(ConfigurationManager.AppSettings["SecretValue1"] + "<br />");
  Response.Write(ConfigurationManager.ConnectionStrings["MyAppConnString"].ConnectionString + "<br />");
%>
Alternatively, you can run the following command which will decrypt the specified section (connectionStrings in this case) in the web.config file directly.

aspnet_regiis -pdf "connectionStrings" "C:\webAppPhysicalLocation"
The process of decryption using the code in the aspx file and the aspnet_regiis -pdf command is a powerful set of tools that can aid you in determing the cause of problems that are occuring with the use of encrypted configuration files. Especially in a server farm environment, it lets you know if the keys have been correctly imported to all the machines participating in the farm and if the web.config file has all the correct settings. 3. Location of key containers:

Depending on how the key containers were installed (per user/for all users), there are 2 separate locations where the key containers are kept: Per User: C:\Documents and Settings\<user_name>\Application Data\Microsoft\Crypto\RSA All Users: C:\Documents and Settings\all users\Application Data\Microsoft\Crypto\RSA

On Vista machines, the location of the container files is: Per user: C:\Users\<user_name>\AppData\Roaming\Microsoft\Crypto\RSA All Users: C:\Users\All Users\Application Data\Microsoft\Crypto\RSA

The files cannot be read as plain text, but if you look through the first few lines, you will be able to determine the names of the key containers on the machine.

4. The following configuration sections CANNOT be encrypted:

  • <configuration>
  • <configProtectedData>
  • <system.runtime.remoting>
  • <runtime>
  • <startup>
  • <mscorlib>
  • <processModel>
  • <satelliteassemblies>
  • <cryptographySettings>
  • <cryptoNameMapping>
  • <cryptoClasses>

5. In case you get a Configuration error while running your application with the following error message: An error occurred loading a configuration file: Could not load file or assembly 'System.Configuration, Version=2.0.0.0, Culture=neutral' or one of its dependencies. The system cannot find the file specified. Then it is most probably because you are missing the PublicKeyToken in the definition for the provider.

6. In case you get an error that the key container could not be opened, check 2 things: - the account that runs the site has permissions to the key container and - the keycontainername specified in the web.config file is the one that exists on your machine.

Other info:

Extremely detailed steps on encryption of configuration sections: http://channel9.msdn.com/wiki/howtoencryptconfigurationsectionsusingrsainaspnet20/

Scott Mitchell article: http://aspnet.4guysfromrolla.com/articles/021506-1.aspx

MSDN documentation: http://msdn.microsoft.com/en-us/library/53tyfkaw.aspx

1 comment:

?!!!@#%* said...

Hi,

You have some insight on how to prevent the decryption in "Deployed Machine".

We encrypt the config in one machine using, export RSA Key. we import into another machine.

But we can issue a Decrypt command at the deployed machine and see the content if logged in as administrator.

Thank you,
Sahridhayan