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.
- 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) - 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
- Machine Key \Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys
- 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.