Encrypting the connection string in ASP.NET V2.0

ASP.Net V2.0 has much improved encryption over v1.x including the ability to encrypt any part of the connection string.  Of course there is some performance overhead to do this so only sections that have sensitive information should be encrypted.

I really battled with part of this today when trying to encrypt the connection string so I thought I would include some of the syntax required, specifically how to reference a particular web.config file within a specific site.  All articles I have found so far reference the default site and not a specific site.

First, this article does a great job of covering the topic so I won't repeat what is covered there.  It's a must read.  In fact, I assume that you've read it and the rest of my blog won't be very easy to understand by itself.
{link is no longer available ... but here's another good reference link.}

You can take a part of the web.config file and encrypt it so that it can't be read unless the key is used to read it.  This helps protect the web.config file and sensitive data that it contains.  ASP.Net automatically decrypts the data as needed. 

I've written information regarding choosing between the Machine Key or User-Level Key which I moved to the bottom of this article in case of interest. 

The aspnet_regiis.exe tool and its syntax

To encrypt the data, you must use a command line utility called aspnet_regiis.exe which exists in the framework folder.  There are two options that work for encryption, -pe and -pef.  Here is what the help file shows:

-pe section         Encrypt the configuration section. Optional arguments:
                    [-prov provider] Use this provider to encrypt.
                    [-app virtual-path] Encrypt at this path level.
                    [-location sub-path] Location sub path.
                    [-pkm] Encrypt/decrypt the machine.config instead of
                    web.config.

-pef section web-app-physical-dir
                    Encrypt the configuration section. Optional arguments:
                    [-prov provider] Use this provider to encrypt.

The difference is how the tool locates the config file to encrypt.

  1. If you use -pe, you can use a relative path like /ApplicationName which is relative to the Default website (SiteID = 1) or a full site path like W3SVC/{SiteID}/root/.  It uses IIS to find out the physical path and will encrypt the web.config file within that path.  (Actually it only encrypts the section of web.config that you specify.)  You can find out how to find the Site ID here: http://weblogs.asp.net/owscott/archive/2005/07/29/421058.aspx
    For example: aspnet_regiis -pe "connectionStrings" -app "w3svc/72/root/" -prov "CustomProvider"  (see the channel9 article in the link above for more details about the custom provider and the connectionStrings section)
  2. The -pef doesn't use IIS at all to locate the config file but allows you to reference the file path directly.  Note that in both cases you don't specify "web.config", that is assumed. 
    For example: aspnet_regiis -pef "connectionStrings" "C:\Inetpub\Site72.com" -prov "CustomProvider"
    Notice that -pef doesn't have an -app parameter, the path immediately follows the section (the part of web.config that is encrypted).

    After noticing these differences today, I brought it up to the ASP.NET team.  I haven't relieved a response yet because I just submitted it but I'm hoping that it's early enough to make these more consistent before the final release of v2.0.  There is one more important difference that I brought up to the ASP.NET team today.  I'll only briefly cover it now since it's not really what I meant to write about.  (For further explanation of the terms, read the article that I've referenced above.)  The -prov usage is different between the two.  With -pe, it's the 'keyContainerName' of the key container that is required but with -pef, it's the 'name' property of the key container that is required.  This doesn't come into play unless you use a custom provider.

The key and its storage location

As for the key and where it is stored, obviously it can't be contained in the same site location as the site or if someone gained access to the web.config file, they would gain access to the key as well, thus defeating the purpose.  So, the key is stored in \Documents and Settings.  There are two levels of key storage

  1. Machine Key  \Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys
  2. User-Level Key \Documents and Settings\{UserName}\Application Data\Microsoft\Crypto\RSA\MachineKeys

In theory, in a trusted environment where everyone on the same server trusts each other, you can use the machine key so that everyone can share the key.  The user-level key is supposed to be used in a shared environment where different applications on the same server don't trust each other.

That's the theory, but what about practical use?  Well, that's a loaded question.  This key can be used by web applications and windows applications, so of course the usage will vary.  There is certainly a use for user-level keys, but in a shared hosted environment, I believe it's actually better to use the machine key and then lock it down with NTFS permissions and a custom anonymous user on the site with impersonation in ASP.NET turned on.  (this doesn't consider a non-anonymous site which has further considerations that I won't cover here). 

My reason: Notice that the User-Level Key requires that a user profile exist for each anonymous user that will use encryption.  Let's say the anonymous user is called I_ScottsSite, then there needs to be a profile in existence which will create the path \Documents and Settings\I_ScottsSite\.  On a shared server, it seems messy to not only maintain the sites themselves but also an array of user profiles in \Documents and Settings\ on the server.  Of course it's possible and acceptable, just not my personal preference.

Instead, using the Machine level Key allows all keys to be in a single location which can have the individual keys locked down using NTFS file level permissions.

There is one important thing to keep in mind.  If you set impersonation (either in machine.config or web.config) then it is the anonymous-user or logged-in-user that needs access to that key. If you don't have impersonation enabled, then it's the worker process user.  By default this is 'Network Service' but in a well planned shared environment, this is usually changed to something else. 

I would say that either are acceptable, but as you can see, even the Machine Level Key can be applicable in a non-trusted shared environment.

7 Comments

  • i have create a connection string in asp.net but i required it reflect in all the pages what can i do

  • Mr.Simplistic:

    You have a point but wouldn't that require write access to the directory where looking at a web.config to get an unencrypted connection string would only require read access.

    Also, if you are using source control and have an unencrypted connection string in your web.config then someone only needs to view the checked in source to get the info.

    I think it is not a solution to the entire problem, just common sense. Like locking a door is a good idea even if it won't stop a serious thief.

  • That channel 9 link at the to of the article is no longer good. Since your article assumes it, would be good to post something to provide a foundation.

  • Thanks for mentioning J. Wolfe. The article isn't around anymore so I updated this to mention another one instead.

  • Hi,
    Great article!
    But I have a little question,
    Normaly we are encrypted the web.config using development machine. But wehn we are deploing, we used another server. My question is how we act this kind of situvation?

    Thanks,

  • Hi Chamin,

    You have 2 options. You can either:
    a) make sure that the machineKey is the same between dev and production so that the web.config file works in both locations. My examples above explain how to do this, although it's from years ago so you may want to review some more current examples on the web.

    b) decrypt the file, copy to the server through some safe method, and then encrypt it again while on the server. Your deployment process will need to do that each time, or it will need to ignore that file so that you only do that on changes. If you have a build server that maintains a dev and production version of web.config, you can encrypt it on the server and then copy that version back to your source control so that it's pushed out with each deployment.

  • I Have little question that i have done step by step

    I have encrypted the connection string and export the keys

    but now when i am publishing website to server then connectionstring not working

    even i have imported the keys to server

Comments have been disabled for this content.