November 23, 2012

Encrypting and Decrypting Web.config Sections in .NET 4.0

Problem
Sometimes we need to store a lot of confidential data in web.config in our production environment (for examples: username\password for impersonation or for connect to database, some appSettings, etc.). And it is not secure to store that as clear text, obviously some people on your server may have access to this file and steal your data.
.NET Framework gives us a good solution. We can encrypt configuration sections in web.config files.

How to Encrypt a section
1. Find aspnet_regiis.exe on your PC.
2. Grand access to ApplicationPool Identity for NetFrameworkConfigurationKey RSA key contanier:
aspnet_regiis -pa "NetFrameworkConfigurationKey" "<ApplicationPool Identity user>"
3. Encrypt a section:
aspnet_regiis -pe "<Path/to/section>" -app "/<YouWebApplication>"
*All these commands require administrative privileges, so if you want to use command prompt for it - don't forget to 'run as administrator'. Otherwise you will get a lot of very strange errors.

It looks very simple...
But let's consider all these steps in more detail.

1. Find aspnet_regiis.exe on your PC
aspnet_regiis.exe is standard .NET Framework tool which allows us to configure our ASP.NET application. Read more about aspnet_regiis on msdn

It is located here (for .NET 4.0):
c:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe
 2. Access to NetFrameworkConfigurationKey
First of all I want to tell you about what NetFrameworkConfigurationKey is.
NetFrameworkConfigurationKey is the name of the RSA key container that to be used when encrypting and decrypting configuration section data. The 'NetFrameworkConfigurationKey' RSA key container with public-private key pair is created when the .Net Framework is installed. Each machine will have a different RSA keys. Therefore you cannot encrypt on one machine and decrypt on another, because RSA keys will be different.

ApplicationPool Identity user should have access to this key container because IIS should decrypt web.config on the fly to get needed values.

To grand access to this key container to a user you can run next command:
 aspnet_regiis -pa "NetFrameworkConfigurationKey" "<userName>"
This key container is defined in machine.config (in .NET Config folder).

If you want to create your own key container (with RSA keys) and not to use standard one, read this article.

Example:
To access NetFrameworkConfigurationKey we need to grand Network Service user, because this is our application pool identity.
c:\Windows\Microsoft.NET\Framework\v4.0.30319>aspnet_regiis.exe -pa "NetFrameworkConfigurationKey" "Network Service"
Result:

3. Encrypt web.config section
One of the best things in section encryption is that we don't need to write any code to support it. We can do all that stuff only by command line. IIS will automatically decrypt on the fly (in memory) sections when it is necessary.

Command to encrypt section:
aspnet_regiis -pe "<Path/to/section>" -app "/<YouWebApplication>"
Path to section is a relative path (from root configuration element in web.config) to target section. We should skip root configuration element in this path. For example a path to identity section in web.config will look like  "system.web/identity"

Example:
We have TestWebsite virtual directory on our IIS web server. Here is web.config:

Now we encrypt appSetting section:
c:\Windows\Microsoft.NET\Framework\v4.0.30319>aspnet_regiis.exe -pe "appSettings" -app "/TestWebsite"
Result:


And connectionStrings section:
c:\Windows\Microsoft.NET\Framework\v4.0.30319>aspnet_regiis.exe -pe "connectionStrings" -app "/TestWebsite"
Result:

Decrypt web.config section
If you need to change manually some values in already encrypted sections you may decrypt section, change values and after that encrypt them one more time.

Command to decrypt section:
aspnet_regiis -pd "<Path/to/section>" -app "/<YouWebApplication>"
Example:
We need to decrypt appSettings section to change some values:
c:\Windows\Microsoft.NET\Framework\v4.0.30319>aspnet_regiis.exe -pd "appSettings" -app "/TestWebsite"
Result:
Summary
I hope this article will help you to make your web sites more secure. As you see it is very easy and doesn't require any additional code. Don't be afraid about IIS, it will automatically decrypt any section on the fly when it is needed.

And I want to summarize all information one more time in one simple example.
If our ApplicationPoolIdenity is Network Service, our website is named TestWebsite and we need to encrypt ssystem.web/identity section we should do next steps:

1. Run cmd as administrator.
2. Go to c:\Windows\Microsoft.NET\Framework\v4.0.30319 folder
3. aspnet_regiis.exe -pa "NetFrameworkConfigurationKey" "Network Service"
4. aspnet_regiis.exe -pe "system.web/identity" -app "/TestWebsite"

13 comments:

達Ming said...

Good Post!!!

Elliott Buckley said...

This is very good example of .net development about Encrypting and Decrypting Web.config Sections in .NET 4.0 platforms very easily and step by step method.

Travis said...

If i have a mixture of .net 2 and .net 4 applications do i need to use the utility that is located in the correct .net version for each file or can i use version 4 for both or version 2 for both??

Rostyslav Yaremchuk said...

Yes, you can use 4 for both,

Anonymous said...

Very useful article.

Unknown said...

Thanks for your article. That how i knew to use RsaKey for my web application.
But there was one thing i could not understand: Why we need create a a Rsa Key, if we don't use this for encrypting and decrypting web.config sections?

Anonymous said...

Some suggestions for improvements:
1. Add the instruction about how to get the ApplicationPoolIdenity.
2. Add the use of "-site' parameter since a web app is not always put under the "Default Web Site".
3. Put all the commands into a batch file, so that it is easier to use.
Below is an example of batch file:

set pathToASPNET=C:\Windows\Microsoft.NET\Framework64\v4.0.30319
cd %pathToASPNET%
:: To grant the ASP.NET identity read access to the default RSA key container
aspnet_regiis -pa "NetFrameworkConfigurationKey" "NT AUTHORITY\NETWORK SERVICE"
aspnet_regiis -pe "connectionStrings" -app "/yourApp" -site "YourWebSite"
:: -----------------------------------------------------------------------------
pause > nul

Anonymous said...

HI,

My question is,
do we need to encrypt on the server or on our local machine.
If we encrypt on our local machine,how the server will be able decrypt as RSA keys are differ from machine to machine?

Rostyslav Yaremchuk said...

Hello, it does not have sense to encrypt on local and server machine. This encryption mechanism is used only to secure your production environment configuration.
If in some cases you need to use encryption on your local machine and server, you need to encrypt web.config separately for each machine. Every machine will have own RSA key due to security reasons.

Anonymous said...

It's a very helpful article.

Unknown said...

Thanks for sharing.

Mihir-d champ is here said...

Excellent Article. Thank you for sharing.

I have a tricky situation where I am not sure about the best practices and how to achieve best solution. I am using VS 2015 and deploying using Publish Profiles. Currently, I have multiple environments with their own profiles and web config transforms. Below are my questions:

• In my main web.config I have my main connection strings which is encrypted (not sure if this should be encrypted or not).
• Should my web.production.config be encrypted in the solution? If yes, how do we apply transforms to encrypted connection strings as xdt:Locator="Match(name)" will not find anything to match in Cipher Value?
• If I want to change my connection string for multiple servers, how do I decrypt it? Do I need to decrypt it on each server?
• Is it a good practice to encrypt each environments (production, QA, staging etc..) connection string and keep it in the solution or not?

Any examples for encryption for different connection strings are highly appreciated

Chand Jogani said...

Very useful article.. Thanks for sharing in details..