Click here to Skip to main content
Click here to Skip to main content

Tagged as

Simplify the Security and Management of Connection Strings in ASP.NET Application

, 8 Jun 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
Since version 2.0, the ASP.NET documentation suggests that we should keep our connection strings in web.config. This raises a number of concerns. There is a better way...

Introduction

So, how do you manage connection strings in your ASP.NET applications? Since version 2.0 of ASP.NET, the most common answer to this was: By placing them all in the <connectionStrings> section of the root <configuration> node of the web.config.

The next logical question would be: How do you make sure that wrong people can't read those strings? By encrypting them, of course. After all, doesn't Microsoft itself enforce this approach? Didn't all well-established publications make this a de-facto method of connection string management in ASP.NET?

Yes, they did. But let's examine all this one more time, this time from a slightly different angle.

Concerns

Indeed, we do need a reliable way to protect our connections from preying eyes. And encryption seems to be the only choice here. But let's list the concerns that programmers typically have when they manage encrypted connections in ASP.NET these days:

  1. The mother of all questions here must be this: Where to store the encryption keys? As soon as you ask that main question, many sub-questions begin to raise. Who should have access to those keys? What if one or more of those individuals leave the company? Who is enforcing the logistics of key handling? What is the recovery procedure if any of those keys was lost or compromised? Who would enforce that procedure? How does he know that he needs to enforce that procedure right now? It's good if your company has a solid "security forcing" process already in place. But what if it doesn't?
  2. You are almost guaranteed to have issues with encrypted connections if your code is running on a web farm, in a cloud or is load-balanced.
  3. You need to code something extra just to make your connections accessible to the rest of your app.
  4. Normally, we need one connection per environment, at least for development and production. It looks really weird when you see all those connections in the same web.config, all having different names like "DevConn_Server_GHYT65TY" and "StagingConn_Local". To combat this, some companies sell "solutions" that manage differences in your configuration files. I have seen one such solution in action at one of our clients. To use it, you must create multiple web.config files in the same web app project, one for each environment. You are supposed to give those files some random unique extensions like web.config.prod or web.config.dev and "register" those files with their server. The software is "smart" enough to rename those files to web.config when it publishes (simply FTPing) the project to the server. What really sucks is that the cost of this "system" is not 10 or 20 bucks. It's several thousand. Amazing...
  5. Here is my "favorite" concern: in our small web development shop, we frequently need to  access many different databases, local and remote ones. I can't just remember dozens of client server locations, database names, logins, passwords and connection specifics. And I don't want to run a project in debug mode every time I need to see the connection to its database in clear text. So, if we would encrypt all our connections, our shop would need some kind of repository where we would keep them in a readable format. And that would pretty much make the entire encryption effort useless for obvious reasons.

Now that we listed our concerns, let's examine what we really want to achieve here.

What Do We Really Want?

  1. We want to restrict certain groups of people from accessing certain resources. For example, developers must be able to connect to development databases but they must not be able to access the production environment or even see the production credentials.
  2. If a person has access to certain resources, he or she should be able to quickly access details of any connection without applying any extra effort.
  3. Our connections can be specific not only to the application itself, but also to the server that currently runs it.
  4. We should have only one connection per database in our configuration files, not all those "DevConn" or "ProdServerConn". And it would be great if names of those connections stay the same no matter which server we are currently on.
  5. We want to be able to set this once for each environment and truly forget about it, even when deploying the entire application, unless some changes have been made to the connection itself.

So, How We Are Going to Do All This? 

Here is what I don't understand: you can achieve all this that I just mentioned above in seconds right now without degrading the security of your application in any way and you were able to do this since the very first public  beta of ASP.NET (April of 2000, I believe). And yet, almost no one brings this to your attention. So, what is it?

Let's do this: create a test web application. Make sure there is a web.config file. Add a new XML file to the root folder of the project, name it AppSettings.config (the .config extension will not allow the run time to serve it over HTTP). Add the following content to that new file:

<?xml version="1.0" encoding="utf-8" ?>
<appSettings>
	<add key="DbConnection" value="-- whatever your connection string is --"/>
</appSettings>

Note that you can omit the XML declaration on top of the file - ASP.NET parser will understand it properly anyway.

Now, add the "file" attribute to the <appSettings> node of your web.config file with the value of the file name of that AppSettings.config file:

<?xml version="1.0"?>
<configuration>

	<appSettings file="AppSettings.config">
		<add key="SomeTestKey" value="SomeTestValue"/>
	</appSettings>

</configuration>

The little dirty secret here is that the "file" attribute tells the parser to load the AppSettings.config file while it reads the web.config. It then "injects" its content to the <appSettings> node. Now you can access the value of that "DbConnection" key from the AppSetttings.config file as you would normally access any other "appSettings" key from the web.config:

using System.Configuration;

namespace Test.Web.Application
{
	internal class Settings
	{
		/// <summary>
		/// Connection string to the database
		/// </summary>
		public static string DbConnection
		{
		    get { return ConfigurationManager.AppSettings["DbConnection"]; }
		}
	}
}

(I assume you're a good professional and rather than accessing configuration values from your pages or forms directly, you have a type that exposes those values as its strongly typed properties.)

I think, it's clear by now that this approach gives us a much better and simpler management of our connections. We can create multiple setting files, one for every server or environment. Those files can contain values specific to their current environments. You create them once, save them on their servers and truly forget about environment-specific settings. Every time you deploy an application to a different environment, you move all application files except for the settings file.

This allows us not to encrypt connections at all. And yet we can reliably control who has access to those connections. Therefore, our first three concerns were just eliminated all at once.

Most developers shouldn't have access to a production environment anyway. With separate setting files in place, developers will never see the production or other "important" connections because they are not the ones who created those files. Programmers can move between projects, leave the company - rest assured that they simply cannot take company's sensitive data with them. So, we eliminated our last concern as well. And we achieved everything that we wanted to achieve.

But wait a second... No one said that everything above applies to DB connections only.

For example, payment gateway credentials for shopping carts. Does the current environment use "sandboxes" or "live" values. What about SMTP credentials? Or server-specific paths? And so on, and so forth. Basically, you can (and should) keep all static environment-independent settings in the web.config itself and move all others to the setting file.

Take a look at the MSDN documentation of <appSettings> node. In the "file" description, notice the phrase "In the .NET Framework version 2.0, you can now include configuration settings in a separate file for all configuration elements that support the configSource attribute". The possibilities are truly endless!

Happy coding, guys. Smile | :)

History

  • 8th June, 2010: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Kikoz68
Web Developer
United States United States
No Biography provided

Comments and Discussions

 
QuestionWhy do all this? PinmemberMyChrims14-Jun-10 15:00 
AnswerRe: Why do all this? PingroupKikoz6815-Jun-10 7:28 
Well, the main concern was not to actually encrypt the connection string but to be able to hide it from the eyes of wrong people. If anything encrypts connections at run-time and decrypts them back when you look at them at design-time, that kind of cancels the main reason why we need to encrypt connections in the first place. Don't you agree?
AnswerRe: Why do all this? PinmemberMyChrims15-Jun-10 10:48 
GeneralRe: Why do all this? PinmemberDrWheetos15-Jun-10 11:11 
GeneralRe: Why do all this? PinmemberMisha19645-Jul-11 13:35 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141220.1 | Last Updated 8 Jun 2010
Article Copyright 2010 by Kikoz68
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid