Introduction
Before .NET there were a number of ways a web application's
settings could be used. One of the most common methods was to declare all
settings in one file and include that file on every page that needed the
settings. This method had its drawbacks, as did the use of the application
variables, database storage and other methods of storage.
With .NET came the web.config file and the ConfigurationSettings
class. Developers could add settings to the web.config file as key-value pairs
in an <appSettings> block.
Listing 1
<appSettings>
<add key="ConnString" value="server=(local);database=pubs;uid=;pwd=;"/>
</appSettings>
Settings could be retrieved as such:
Listing 2
MyConnectionString = ConfigurationSettings.AppSettings("ConnString")
This was a great improvement, but still had its drawbacks. The
settings were loosely typed and there was no Intellisense, so a developer had
to remember or double-check a setting's key. If more than a key-value pair was
required, entire sections could be added to the web.config, but they required a
custom handler to be written. Settings could also be stored in external
configuration files, but these also required custom handlers, and as such, were
not commonly used. Also, settings were stored in plain text and anyone reading
the settings file could potentially gather information they should not have.
Settings could be encrypted, but that meant writing code to encrypt and decrypt
the settings. Plus, encryption keys were not easily migrated between different
machines. The difficulty often prevented the use of encryption.
In Visual Studio 2005 and .NET 2.0, Microsoft has made some
great enhancements, both in how configuration information can be accessed and
how this information can be used. Since storing connection strings was very
common, new sections (including a ConnectionString section) were added to the
web.config schema and these sections can be encrypted and decrypted natively. All
settings can be managed easily at design time through Visual Studio 2005 tools.
A new ConfigurationManager class has been added to the framework, which
provides a convenient way to get and set configuration properties at run time.
Settings can also be easily placed in external configuration files and still
managed with the configuration tools. Whew! That is a lot of good
stuff--let's get started! One note though, although we are focusing on ASP.NET
web applications, all of these improvements and more are available in Windows
forms applications.
Getting Started
One of the first decisions you will need to make is where to
store the settings. In a web application, you only want to store application
settings in your configuration files; user settings are best stored by using
the Profile provider. This is because user settings can not be feasibly
separated into individual My Documents folders, like they can with a Windows
application.
Settings which are not likely to change very often, such as
connection strings, can be stored in the web.config file. Since .NET 2.0 now
allows your code to easily write configuration settings, it is possible to
update your web.config at runtime (by using an admin tool you created). However,
changes to the web.config will cause an application restart each time you write
to this file and you obviously do not want to do this very often. Instead, you
want to use an external configuration file to store settings that will be
updated.
A new property of the configuration section elements has
been added in .NET 2.0 - configSource. You use configSource to specify the
name of the external file containing that section's settings, such as the
following:
Listing 3
<appSettings configSource="appsettings.config"/>
Note: For security reasons, it is a good idea to give your
settings files a .config extension, since files with this extension will not be
served to the Internet.
When you specify a file using configSource, you must put all
of that section's settings in the external file. If you only specify a file by
using the older 'file' property, the settings in the external file will be
merged with the settings in the web.config file.
The structure of the external file must replicate that of
the section it is replacing.
Listing 4
<appSettings>
<add key="MySetting" value="ValueOfMySetting"/>
</appSettings>
Using configSource does not completely solve the problem of
application restarts when the file is updated. To prevent application restarts
when your configuration file is updated, you need to do a little editing in
your machine.config file (this is probably not an option if you are on a shared
host). Find your machine.config file, usually found in C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG,
and make a backup copy- just in case if you mess up with the original file. Open
the file and locate the section element for the configuration section you need
to modify. It will look similar to Listing 5 below (line breaks added to fit
this format).
Listing 5
<section name="appSettings"type="System.Configuration.AppSettingsSection,
System.Configuration, Version=2.0.0.0,Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a"restartOnExternalChanges="false"
requirePermission="false" />
The restartOnExternalChanges setting needs to be set to false.
If the section tag does not include this attribute, you can add it. The
appSettings by default is already set to false, but other configuration
sections may not be. Changing the machine.config will cause applications to
restart, so try to make all changes at once.
New Configuration Sections
As mentioned above, several new configuration sections have
been added to the web.config schema. These sections can be placed in external
files using the configSource property, just as with appSettings. These new sections
include:
Section
|
Use
|
<connectionStrings>
|
Lists connection strings, as built using the new
management tools described below.
|
<siteMap>
|
Stores information about site map providers.
|
<membership>
|
Stores information about membership providers.
|
<smtpMail>
|
Stores settings used by the SMTP service, including server
name, default From and Subject values.
|
A complete list of new and updated configuration sections
can be found in the .NET SDK by searching for "new configuration
sections" (the .NET SDK can be downloaded from http://asp.net).
The important thing to note is that we are no longer limited to using the
appSettings section. We have several specialized sections to suit our needs
and the information in these sections can be encrypted.
Setting Values at Design Time
The .NET 2.0 Framework includes two management tools which
can be used to create and change application settings. One tool is a web-based
tool with limited functionality and the other is an MMC snap-in with greater
functionality.
The Website Administration Tool can be launched from within
Visual Studio 2005 by navigating Website >> ASP.NET Configuration. The built-in
web server will start and the administration tool will be launched.
Figure 1: Web Site Administration Tool
In addition to application settings, you can also configure
providers, such as the Membership provider, and set up security settings (such
as new website users or roles). In this article, we will only be looking at
the Application settings tab. This tool allows us to create and edit settings
in the appSettings section.
Figure 2: Application Settings Tab
To create new application settings, click on the
"Create Application Settings" link. On the next page, enter the setting's
name (which will be the key in our web.config), the value and click Save.
After our web.config is updated, we will be given the option of adding another
setting or returning to the Applications settings tab.
Figure 3: Creating a New Application Setting
If we configured an external settings file using
configSource, our new setting is saved in that file. Otherwise, our new setting
is saved in the web.config file.
Figure 4: New Setting Stored in External File
Clicking the "Manage application settings" link
allows us to edit or delete settings. Note that the key cannot be changed,
only the value.
Figure 5: Editing an Application Setting
The MMC snap-in is installed as part of the IIS control
panel (not found in XP Home Edition) and is launched by:
1.
Drill down the Control Panel >> Administrative Tools >>
Internet Information Services.
2.
Expand the local computer node.
3.
Expand Web Sites node to obtain a list of websites. On a Windows 2000
or XP, you will have to expand the Default Web Sites to obtain a list of all
the subwebs on your system.
4.
Right-click on the web whose settings you wish to change and select
Properties.
5.
Select the new ASP.NET tab (see Figure 6).
Figure 6: The ASP.NET Control Panel
Clicking the "Edit Configuration" button opens the
ASP.NET Configuration Settings tool. Settings created with the Configuration strings
manager become part of the connectionStrings section; Application Settings become
part of appSettings. As you can see, this tool allows us to control a great
deal more of the application than the Website Administration Tool, but we are
only interested in this tab.
Figure 7: Editing MySetting
Retrieving Values at Run Time
All the added application setting sections and improved
functionality led to the addition of a new class--the WebConfigurationManager
class (link to documentation in References). In its simplest use, the
WebConfigurationManager allows us to read settings from appSettings and
connectionStrings in a single line of code.
Listing 6
Dim MyString as String = WebConfigurationManager.AppSettings("MySetting").ToString
Other sections can be read by using the GetSection method.
Some sections have specific class, including the Pages section (PagesSection)
and connectionStrings section (ConnectionStringSettings class). Custom
settings sections will use the ConfigSection base class.
As an example, if we want to list all of the namespaces in
the Pages section, we could use code, such as:
Listing 7
Protected Sub Page_Load(ByVal sender As Object, ByVale As System.EventArgs) Handles Me.Load
Dim MyString As String
Dim pagesSection As PagesSection
Dim i As Integer
pagesSection = CType(WebConfigurationManager.GetSection("system.web/pages"),PagesSection)
For i = 0 To pagesSection.Namespaces.Count - 1
MyString + = pagesSection.Namespaces(i).Namespace& "<br />"
Next
Label1.Text = MyString
End Sub
Setting Values at Run Time
Some applications are built with administration tools that
can update the application's settings. In ASP.NET 2.0, we can modify settings in
the web.config in our code. This is something we would want to do in response
to a button's click event. The sample code below shows how easy it is to
modify an application setting in ASP.NET 2.0.
Listing 8
Protected Sub btnUpdateSetting_Click(ByVal sender AsObject, ByVal e As System.EventArgs) _
Handles btnUpdateSetting.Click
Dim cfg As Configuration
cfg = WebConfigurationManager.OpenWebConfiguration("~")
Dim setting As KeyValueConfigurationElement = _
CType(cfg.AppSettings.Settings("MySetting"),KeyValueConfigurationElement)
If Not setting Is Nothing Then
setting.Value = "New Value Setting"
cfg.Save()
End If
End Sub
Encrypting Configuration Settings
Most sections of the web.config can be encrypted, but there
are a few things you need to think about before you do this. Unfortunately,
there is no visual tool that will encrypt configuration settings; our two
choices are either the command-line tool aspnet_regiis or by using code. There
are also two encryption algorithms (RSA and DPAPI), each with its own
considerations.
With either algorithm, the keys can be stored at the machine
level or at the user level. If you run a server with only your applications on
it, and there is not an issue with all settings being encrypted with the same
key, then machine storage would work. If you need to ensure all your
applications' settings are encrypted with different keys, ensure that each
application runs in its own application pool and each pool has its own identity.
Then you will need to pick the user storage for the keys.
Microsoft's Patterns and Applications Group has good
examples using DPAPI or RSA (links are in the references). Each of these articles
discusses the merits of each algorithm and should be considered required
reading in addition to this article. One particular advantage that RSA has
over DPAPI is that the RSA keys can be exported to an XML file and then copied
to other machines. This is especially useful for developers who can create RSA
keys on a production server then export and copy them to test and development
machines, so configuration settings do not need to be encrypted in each
environment.
In brief, we encrypt configuration sections, such as the
following:
Listing 9
aspnet_regiis -pe "<config section>" -app"/<application name>" -prov "<providername>"
For instance, if we wanted to use RSA to encrypt the
appSettings section in MyApplication, we would issue the following command.
Listing 10
aspnet_regiis -pe "appSettings" -app"/MyApplication"
Since RSA is the default provider, we do not need to specify
the encryption provider. If we wanted to do the same thing with DPAPI, we
would issue the following command.
Listing 11
aspnet_regiis -pe "appSettings" -app"/MyApplication" -prov "DataProtectionConfigurationProvider"
If you are on a shared host, you probably cannot execute
command-line utilities and you definitely want to use the user store. Your
only option to encrypt your configuration settings is to use code in your
application. David Hayden (link in references) has a good example in C#; the
VB.NET translation is below.
Listing 12
Protected Sub btnEncryptSettings_Click(ByVal senderAs Object, ByVal e As System.EventArgs) _
Handles btnEncryptSettings.Click
Dim config As Configuration =WebConfigurationManager.OpenWebConfiguration("~")
Dim section As ConfigurationSection =config.GetSection("appSettings")
If Not section Is Nothing And Notsection.SectionInformation.IsProtected Then
section.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider")
config.Save()
End If
Dim MyString As String
MyString =WebConfigurationManager.AppSettings("MySetting").ToString
Label1.Text = MyString
End Sub
When we deploy our application, we do not want encryption
code hanging around. Ideally, this part of the example will be part of a
separate project that is deployed with the production application. The
encryption page is then loaded and then deleted from the production server.
The production application is already set to use the configured settings.
The really good news is, after we have encrypted our
configuration settings, we do not need to write any code to decrypt the
settings. ASP.NET automatically decrypts the settings when they are read.
Summary
The .NET 2.0 Framework brought about many improvements, including
a new class to manage web application settings. The WebConfigurationManager
class adds support for encrypted sections, as well as new sections, and the
ability to update settings from within an application.
References
ASP.NET Quickstart Tutorial, "Using the Management API",
http://www.asp.net/QuickStart/aspnet/doc/management/mgmtapi.aspx
Channel 9, " How To: Encrypt Configuration Sections in
ASP.NET 2.0 Using RSA", http://channel9.msdn.com/wiki/default.aspx/Channel9.HowToEncryptConfigurationSectionsUsingRsaInAspNet20?diff=y
Esposito, D., "Introducing Microsoft ASP.NET 2.0",
2005, Microsoft Press.
Hayden, D., "Encrypt Connection Strings AppSettings and
Web.Config in ASP.NET 2.0 - Security Best Practices", http://davidhayden.com/blog/dave/archive/2005/11/17/2572.aspx
Meier, J.D., et al., "How To: Encrypt Configuration
Sections in ASP.NET 2.0 Using DPAPI", http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/PAGHT000005.asp
Meier, J.D., et al., "How To: Encrypt Configuration Sections
in ASP.NET 2.0 Using RSA", http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag2/html/PAGHT000005.asp
MSDN Library, "PagesSection Class", http://msdn2.microsoft.com/en-us/library/system.web.configuration.pagessection(VS.80).aspx
MSDN Library, "WebConfigurationManager Class", http://msdn2.microsoft.com/en-us/library/ms151430.aspx
Schofield, S., "ASPdot.NET: Create Export & Encrypt
connection string on server and dev machine with ASP.Net 2.0", http://www.aspdot.net/articles/encryptedconnstring/