Ultimate Guide to the Web.Config File for ASP.Net

The web.config file is an XML file located within the root of the application folder and used to configure the application.

By Tim TrottC# ASP.Net MVC • January 6, 2009
2,171 words, estimated reading time 8 minutes.
Ultimate Guide to the Web.Config File for ASP.Net

The web.config file, which is used by IIS, plays a crucial role in configuring both the application and the server. It controls various aspects of the application's behaviour, including authentication, error pages, debug information, session configuration, and more.

What is the web.config files?

The web.config file is an XML file located within the root of the application folder. It is used to store configuration settings for the current ASP.Net web application. Settings within the web.config are specific to an application instance. machine.config should be used for server-wide settings. Settings in the web.config will override the machine.config settings.

The web.config file can consist of any valid XML tag; the root tag of the document is always 'configuration'. Depending on your application's needs, you can include any number of tags within this tag. For instance, you can configure the application's session state, set the application's default culture, or specify the application's error-handling behaviour.

Some of the main sections are system.web and appSettings, which are looked at in more detail below.

System.Web Section of Web.Config

The 'system.web' section, which is the root element for the configuration, is a crucial part of the web. config file. It controls various aspects of the application's behaviour, such as session state, authentication, and compilation settings.

You can set debug mode on and off in the compilation element.

xml
<compilation debug="false" strict="false" explicit="true">

You can set the custom asp.net error pages from within the system.web as well:

xml
<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
  <error statusCode="403" redirect="NoAccess.htm" />
  <error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>

When setting mode to RemoteOnly, the error page redirects will not be handled when viewing the page on localhost. Other values are On (rules are always processed) and Off (rules are never processed).

You can also secure web applications in this area of the web.config, a topic covered in a future tutorial.

Web.Config appSettings Section

The 'appSettings' section, another important part of the web. config file, is used to store application-specific settings. These settings can include connection strings, server names, file paths, and any other settings that are dependent on the environment in which the application is running.

Shown below is a minimal appSettings section that holds a connection string.

xml
<appSettings>
  <add key="ConnectionInfo" value="server=(local);database=Northwind;Integrated Security=SSPI" />
<appSettings>

You can then access the data stored in the web.config appSettings section from within the C# code behind like this:

C#
string connectionString = ConfigurationSettings.AppSettings["ConnectionInfo"];

This powerful technique can be used to eliminate any hard-coded data and allow applications to be more flexible. Any changes can be made without the need for recompilation, giving you full control over your application's behaviour.

Custom Error Pages

There is a setting in the web.config that you can use to redirect errors for remote users (if you view the page on the localhost web server, you can see the error and debug the code accordingly).

xml
<customErrors defaultRedirect="myErrorPage.aspx" mode="RemoteOnly"/>

If you do not wish errors to be shown, not even on localhost, set the mode to On instead of RemoteOnly.

You can also set custom error pages for specific errors your code cannot process, such as a 401 unauthorised, 404 Not Found page or a 500 internal error. Add extra lines and change the attributes to meet your needs.

xml
<customErrors mode="On">
  <error statusCode="404" redirect="/errorpages/404.aspx" />
  <error statusCode="500" redirect="/errorpages/500.aspx" />
</customErrors>

Web.config Encryption

Protecting sensitive data, such as connection strings, is always a good idea, as they are not accessible to anyone without proper authorization. It is highly unlikely that anybody could read these values since they would need direct access to the server, but it is still best practice to encrypt such data. Luckily, Microsoft .Net provides several methods for encrypting connection strings, or any other keys, in the web.config, ensuring the security of your application.

Let's take a look at a simple web.config file.

xml
<configuration>
 <appSettings>
  <add key="myKeyName" value="myValue"/>
  <add key="ProtectMe" value="This is a secret!" />
<appSettings>
  <connectionStrings>
    <add name="myDatabaseConStr" connectionString="Data Source=myServerAddress;Initial Catalog=myDataBase;User Id=myUsername;Password=myPassword;" providerName="System.Data.SqlClient" />
  </connectionStrings>
  <system.web>
    <compilation debug="true"/>
    <authentication mode="Windows"/>
  </system.web>
</configuration>

Method #1 - C#

The first encryption method requires some C# code in the background, which is an encryption method, and the other is for decryption. They are very simple, and both use the WebConfigurationManager class. This code has been wrapped into a utility class, so all you need to do is copy and paste the code into a new class file.

C#
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Web.Configuration;

/// <summary>
/// Utility class for encrypting and decrypting the web.config file
/// </summary>
public static class WebConfigEncryption
{
  /// <summary>
  /// Encrypt a section of the web.config
  /// </summary>
  /// <param name="sectionToEncrypt">Name of the section to encrypt</param>
  /// <param name="encryptionProvider">One of the EncryptionProviders to use</param>
  public static void EncryptSection(string sectionToEncrypt)
  {
    Configuration config = WebConfigurationManager.OpenWebConfiguration(HttpContext.Current.Request.ApplicationPath);
    ConfigurationSection section = config.GetSection(sectionToEncrypt);

    if (!section.SectionInformation.IsProtected)
    {
      if (!section.ElementInformation.IsLocked)
      {
        section.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider");
        config.Save(ConfigurationSaveMode.Full);
      }
    }
  }

  /// <summary>
  /// Decrypt a section of the web.config
  /// </summary>
  /// <param name="sectionToEncrypt">Name of the section to decrypt</param>
  public static void DecryptSection(string sectionToEncrypt)
  {
    Configuration config = WebConfigurationManager.OpenWebConfiguration(HttpContext.Current.Request.ApplicationPath);
    ConfigurationSection section = config.GetSection(sectionToEncrypt);

    if (section.SectionInformation.IsProtected)
    {
      if (!section.ElementInformation.IsLocked)
      {
        section.SectionInformation.UnprotectSection();
        config.Save(ConfigurationSaveMode.Full);
      }
    }
  }
}

You will notice the use of "RsaProtectedConfigurationProvider" in the encryption code. This specifies the ProtectedConfigurationProvider that .Net will use to encrypt the section.

You can call this code using the following methods to encrypt and decrypt the section.

C#
public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
      // Encrypt appSettings section
      WebConfigEncryption.EncryptSection("appSettings");

      // Decrypt appSettings section
      WebConfigEncryption.DecryptSection("appSettings");
    }
}

You can easily substitute appSettings for connectionStrings to encrypt connection strings or instead of.

Let's have a look at the result from the RsaProtectedConfigurationProvider on the web.config from above.

xml
<configuration>
  <appSettings configProtectionProvider="RsaProtectedConfigurationProvider">
    <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns="http://www.w3.org/2001/04/xmlenc#">
      <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
        <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
          <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
          <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
            <KeyName>Rsa Key</KeyName>
          </KeyInfo>
          <CipherData>
           <CipherValue>3YKipPu2e83QASir3owfIs0pmq97VR9dWkPfXouYNArz+Uo2sMxte7Gp303ag6+WMYGqi5sAUuFmJW3KSOnuFyVG0NDneA42eUo6ktG4LVaQoA5DIFJT02PSD5mzkf5VTPvupAuokQLGx9ZNv9qYA+HSXEcn3AKNBvxgBkagKg8=</CipherValue>
          </CipherData>
        </EncryptedKey>
      </KeyInfo>
      <CipherData>
        <CipherValue>X8sdfco1OaOauIbA31Osb+4a+7xeYqiWJa45l1X4ttKvkMM4kZ7Uj6c9yxW2MjwkisIdhPWJHtobjfw8JNe2qnbygBolL3su/iQde5s5HAdvVOcJIOHfeQ==</CipherValue>
      </CipherData>
    </EncryptedData>
  </appSettings>
  <connectionStrings>
    <add name="myDatabaseConStr" connectionString="Data Source=myServerAddress;Initial Catalog=myDataBase;User Id=myUsername;Password=myPassword;" providerName="System.Data.SqlClient" />
  </connectionStrings>
  <system.web>
    <compilation debug="true"/>
    <authentication mode="Windows"/>
  </system.web>
</configuration>

The first thing we noticed was a lot of extra information in the appSettings section. The first part of the new data contains namespaces that .Net uses to use later and decrypt settings. The two important parts of the new data are the "CipherValue" keys. If you look at the structure of the new appSettings there is a KeyInfo with CipherData and a CipherData out on its own. The KeyInfo contains an encrypted encryption key. That means a key (or password) has been generated to encrypt our data. This has then been encrypted with the machine key and stored in the web.config file. The CipherData string contains an encrypted version of our appSettings key/value pair.

Since the encrypted encryption key is encrypted with the machine key (try saying that after a few pints!), it is difficult to distribute the encrypted web.config to a different server; we will need to create custom keys and RSA providers. We will investigate this problem in a future tutorial.

We can also use the decryption code to decrypt the appSettings and return the web.config to its original state.

I have created a simple utility class to encapsulate these functions; the code can be downloaded at the end of this tutorial.

Method #2 - Command Line

The other method for encrypting web.config does not involve any code; instead, it is based on the command line tool aspnet_regiis.

This command line tool is in the %windows%\Microsoft.NET\Framework\versionNumber folder or runs directly from the Visual Studio command prompt.

To encrypt a section of the web.config:

C:\>aspnet_regiis -pe "appSettings" -app "/YourAppVirtualDir" -prov "RsaProtectedConfigurationProvider"

And to decrypt it again:

C:\>aspnet_regiis -pd "appSettings" -app "/YourAppVirtualDir"

Regardless of the method, .Net will automatically decrypt values when you read them back at runtime, so any existing calls to ConfigurationSettings.AppSettings or reading connectionStrings do not need to be modified.

Using encrypted web.config in web farms

As previously mentioned, the encryption is based on the machine key stored in the machine.config and is unique to each server. Because of this, decryption will only work on the server on which it was encrypted. However, there is a way around this problem: using key containers.

The process is fairly simple; you encrypt the web.config on one machine, export the key container and import it on all the other servers.

Let's have a look at the process.

Creating an RSA Key Container

We will use the ASP.NET IIS registration tool to create an RSA key container. We must give the key container a name to identify the container used by the RsaProtectedConfigurationProvider.

The following command will create an RSA key container named 'SampleKeys' that is a machine-level key container and is exportable.

aspnet_regiis -pc "SampleKeys" "exp

The following example shows the configProtectedData section of a web.config file. The section specifies a RsaProtectedConfigurationProvider that uses a machine-level RSA key container named SampleKeys.

xml
<configProtectedData>
  <providers>
    <add name="SampleProvider" type="System.Configuration.RsaProtectedConfigurationProvider, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a processorArchitecture=MSIL" keyContainerName="SampleKeys" useMachineContainer="true" />
  </providers>
</configProtectedData>

As a security precaution, generated RSA key containers are protected by server access control lists (ACLs). Before using the key container, we must allow the ASP.NET worker process to have read access. In most cases, the worker process uses the NETWORK SERVICE profile. You can check this by viewing the application pool properties in which the application is running. The following command will grant the network process access to the key container.

aspnet_regiis -pa "SampleKeys" "NT AUTHORITYNETWORK SERVICE"

Next, we must allow the application's Windows identity access to the machine key container named NetFrameworkConfigurationKey, the key container specified for the default provider.

aspnet_regiis -pa "NetFrameworkConfigurationKey" "NT AUTHORITYNETWORK SERVICE"

The NetFrameworkConfigurationKey RSA key container is the default for commands issued by the Aspnet_regiis.exe tool. The preceding command could, therefore, also be issued as the following:

aspnet_regiis -pa "NT AUTHORITYNETWORK SERVICE"

Exporting an RSA Key Container

Now, we are over the worst of the process. The next task is to export the key container to an XML document. This is also done using aspnet_regiis.exe. The following command will export our SampleKeys to a file called keys.xml.

aspnet_regiis -px "SampleKeys" keys.xml -pri

For security, after exporting an RSA key container to an XML file, copy the XML file to a location external to the server and delete the XML file. This reduces the chance of an attacker gaining access to your RSA key container and thereby the ability to decrypt Web.config files encrypted using that RSA key container.

Importing an RSA Key Container

Almost done. The final step is to import the key container into each other web farm server. Copy the keys.xml onto the destination server and import it using the following command:

aspnet_regiis -pi "SampleKeys" keys.xml

Once again, delete the XML file from the server when finished.

And now we are done!

There is a more in-depth walkthrough on the Microsoft website Creating and Exporting an RSA Key Container

About the Author

Tim Trott is a senior software engineer with over 20 years of experience in designing, building, and maintaining software systems across a range of industries. Passionate about clean code, scalable architecture, and continuous learning, he specialises in creating robust solutions that solve real-world problems. He is currently based in Edinburgh, where he develops innovative software and collaborates with teams around the globe.

Related ArticlesThese articles may also be of interest to you

CommentsShare your thoughts in the comments below

My website and its content are free to use without the clutter of adverts, popups, marketing messages or anything else like that. If you enjoyed reading this article, or it helped you in some way, all I ask in return is you leave a comment below or share this page with your friends. Thank you.

There are no comments yet. Why not get the discussion started?

New comments for this post are currently closed.