How to encrypt web.config connection strings without recycling the app pool - asp.net

Goal
Break the connectionStrings section out of the web.config by placing it into an external configuration file while being able to encrypt/decrypt the connection strings on the fly without causing the application pool to recycle (which creates an undesired service outage).
Attempt #1
I broke the connectionStrings section out by copying it into a newly created connectionStrings.config external configuration file and then replaced it with <connectionStrings configSource="connectionStrings.config"/> in the web.config
After the sites came back up, I ran C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe -pef "connectionStrings" %path_to_web.config_folder% via the command prompt to encrypt the connection strings
Result
The websites temporarily stopped responding immediately after running the above command because the app pool recycled due to a web.config change. However, I checked and the web.config was only "touched," i.e. the file's Last Modified Date got updated although its content didn't actually change. The connection strings in connectionStrings.config were successfully encrypted, though!
I figured there might have been some fundamental feature/limitation of aspnet_regiis.exe which automatically touches the web.config after doing its thing, so I looked for an alternative approach to encryption. This led me to...
Attempt #2
I opened the web.config in the Microsoft Enterprise Library Configuration tool (ran as administrator)
Chose the RsaProtectedConfigurationProvider option from the drop-down as the Protection Provider under the Database Settings block
Saved the file
Result
Doing this literally took the connectionStrings block from the connectionStrings.config file and inserted it back into the web.config encrypted. This circumvented the whole point of using an external config and defeated the purpose of trying this approach out in the first place!
Question
Is it even possible to encrypt web.config settings without having the app pool recycle before taking effect? I can't find this answer in Microsoft's documentation or anywhere for that matter.
Thank you!

Related

How is everyone storing connectionstrings?

I was wondering if people could post their solution to the ongoing problem of local databases and different connectionstrings among many developers in one project within source control?
More specifically, I'm talking about the problem where a project that is in source control and has many developers with a local database each. Each developer has their own connection string (named instance, default instance, machine name, username, password, etc). Every check in overrides the previous version and pulling the latest version results in using someone else's connection string.
So, people, which solution are you using for this problem? Extra points for explanations on why their solution works, pros, and cons.
EDIT
Keep in mind that this answer shouldn't be targeted only to an enterprise environment where you have full control of the setup. The right solution should work for everyone: enterprise, startup, and open source devs.
Thanks!
To me, your question seems to imply one of two outcomes:
A connection string is specified in the Web.config file that is generic enough to work for all local versions of the database. You've indicated that this isn't an ideal setup in environments where you don't have complete control.
Each developer is required to supply his or her own connection string that is never checked into source control.
A few others have already covered the first scenario. Use localhost and follow a convention for the database name. For option 2, I'd recommend specifying a config source that doesn't get checked into source control:
<configuration>
<connectionStrings configSource="connectionStrings.config"/>
</configuration>
EDIT:
connectionStrings.config
<connectionStrings>
<add name="Name"
providerName="System.Data.ProviderName"
connectionString="Valid Connection String;" />
</connectionStrings>
From: http://msdn.microsoft.com/en-us/library/ms254494(v=vs.80).aspx
connectionStrings.config would be a file in the root of the project that you specifically excluded from source control. Each developer would be required to provide this file when working locally. Your production connection string could be substituted via a Web.config transformation on build / deployment.
All of our development stations are setup somewhat the same.
We use integrated authentication to the database, so no user/password needs to be stored.
Everyone uses the default instance.
Since they are all local databases, you can user localhost.
Same database name
So a connection string might end up being:
Data Source=localhost;Initial Catalog=TheDatabaseName;Integrated Security=SSPI;
And everyone uses that.
We have a test database that runs on it's own server. It is just test data actually replicated from the live server every night.
All developers use this for testing. It is true data but non critical as it is a day old.
We store the connection strings in the web.config of course. I have a function to get the connection string from the web.config and I just look if it is localhost return the test connection string. if not then return the live connection string.
This works for us. And we just don't use local databases.
I've seen various methods used.
i) You only maintain a live connection string and developers make modifications to the relevant module and never check it in.
ii) An app.config is maintained with the connection strings and it is a shared file as far as source control is concerned.
iii) In debug config, connection string details are passed in the command line from the IDE.

Encrypting Web.Config

I am going to encrypt appSettings in Web.config:
Many ways worked on local, but the issue is I need to encrypt/decrypt webconfig many times on production server, and I don't want to Network admins, to change web.config permissions every time we do this?
is there any better way of securing appsettings?
aspnet_regiis -pe is the method Im assuming you are referring to.
First, this should occur only when you deploy to the server (which you are prob planning on). Secondly, net admins just need to run an admin prompt to do this - they don't need to change permissions on the file. I talk about this a little in the video at: http://channel9.msdn.com/Events/TechEd/NorthAmerica/2011/DEV333
If you want to secure the appsettings content this way you have to do it. But there may be issues if you want to deploy the web app in a farm. In the case you may have to look at Creating and Exporting an RSA Key Container. Or you can have the appsettings values to a database and read it from there.
I would recommend you have your application encrypt the values after it is started. That will make sure that the values are always encrypted.
Then keep the values unencrypted in your source control tree or the installer files that you use to deploy the application.
You can use aspnet_regiis.exe application that comes with the .net framework(NOTE: every framework is having a different aspnet_regiis.exe application)
If your application is in framework 2.0 you can use aspnet_regiss.exe -pef or aspnet_regiss.exe -pe for encrypting the selected section from your configuration file.
for more information you can refer to the link
http://msdn.microsoft.com/en-us/library/k6h9cz8h(v=vs.80).aspx
Hope the information gets you a resolution!!!!!!
:)

ASP.NET connection string deployment best practice

I've collected a (hopefully useful) summary of the ways I've researched to accomplish the subject of this post, as well as the problems I have with them. Please tell me if you've found other ways you like better, especially if they resolve the problems that the methods I mention do not.
Leave connection strings in web.config and use XDT/msdeploy transformation to replace them with settings according to my active build configuration (for example, a web.PublicTest.config file). My problem with this is I merge and bury a few server-specific settings into an otherwise globally identical file with many configuration elements. Additionally, I cannot share connection string definitions among multiple peer-level applications.
Specify a configSource="DeveloperLocalConnectionStrings.config" value for connection strings in web.config, and XDT transform this value to point to one of the multiple environment-specific files in my code-base. My problem with this is I send passwords for all my environments to all destinations (in addition to SVN, of course) and have unused config sections sitting on servers waiting to be accidentally used.
Specific connection strings in the machine.config file rather than web.config. Problem: who the heck expects to find connection strings in the machine.config, and the probability of surprise name collisions as a result is high.
Specify a configSource="LocalConnectionStrings.config", do not transform the value, and edit the project xml to exclude deployment of the connection string config. http://msdn.microsoft.com/en-us/library/ee942158.aspx#can_i_exclude_specific_files_or_folders_from_deployment - It's the best solution I've found to address my needs for a proprietary (non-distributed) web application, but I'm paranoid another team member will come one day and copy the production site to test for some reason, and voila! Production database is now being modified during UAT. (Update: I've found I can't use one-click publish in this scenario, only msdeploy command line with the -skip parameter. Excluding a file as above is the same as setting it to "None" compile action instead of "Content", and results in the package deleting it from the deployment target.)
Wire the deployment package up to prompt for a connection string if it isn't already set (I don't know how to do this yet but I understand it is possible). This will have similar results to #4 above.
Specify a configSource="..\ConnectionStrings.config". Would be great for my needs, since I could share the config among the apps I choose, and there would be nothing machine-specific in my application directory. Unfortunately parent paths are not allowed in this attribute (like they are for 'appSettings file=""' - note also that you can spiffily use file= inside a configSource= reference).
p.s. some of these solutions are discussed here: ASP.Net configuration file -> Connection strings for multiple developers and deployment servers
When using SQL Server, you can also use Integrated Security / SSPI and add the WebServer Computer Login to the Sql Server.
That way you dont have to expose anything in the web.config and you can grant roles to that login like you would to any other DB user.
Though you have to understand the implications and security considerations to be taken, because any malicious code executed as THAT machine will have access to the Sql Server.
with regards
Ole
Use the hostname as key for the connectionstring, that way you can choose the datasource automagically. Make sure the choosing routine is not buggy (change hostname - test!)...
Don't put it in the web.config, write an ini file, that way there is no XML encoding.
Encrypt the password therein, with private/public key (RSA/PGP). Don't ever use cleartext, or a symmetric key, which is just as bad.
Check my following blog post: Protecting asp.net machine keys and connection strings
If you do use Quandary's answer, use a key that's not in the site's folder, just like asp.net does with protected config sections.
We manually approve changes to the web.config that go into staging/production. We use integrated instead of username based where possible, but an option we've used in the later case is to just have placeholders for the username/passwords in SVN.
We've used separate config files in the past, but we have run into other type of issues with web.config modifications, so we have been locking it in a single file lately.

ASP.Net configuration file -> Connection strings for multiple developers and deployment servers

I have a team of three developers, two of whom use a standard local test database, one of whom uses his own database and there is also a server environment with a production database and a testing database.
This amounts to multiple connection strings required.
The web.config file periodically gets updated and keeps having to be changed by each developer when a source control update is performed, as well as the fact that sometimes a developer accidentally checks in his personal web.config file change with his connection string, which temporarily interrupts us after running a subsequent update from source control.
What can I change so that the web.config file can be committed/updated as often as is necessary and not result in broken connection strings for other developers or require modifications before it can be uploaded to the testing or production environments?
You might want to look at replacing the ConnectionStrings section of the Web.Config with a Config Source file, commit the LIVE set of connection strings into source control, but not include them in the actual solution.
Information on using the configSource attribute can be found in the section "Using External Configuration Files" in the document:
Connection Strings and Configuration Files
This has the advantage that developers could have their own settings that don't get checked into the main Web.Config. The potential downside is that it's yet another file that you have to worry about, and depending on how you're getting the latest version out of source control might not help (i.e. if you go to your SC client and say "Get latest" that would overwrite the file, whereas if you are in Visual Studio, right click on the solution/project and select "Get Latest" that will only get files in the projects).
For the question regarding the testing and production environments, you can make use of the Visual Studio Web Deployment Projects. With that, you can define sections in the web.config that will be replaced when you build the deployment package for the test / prod server.
You could use the Enterprise Library Data Access Block to handle your database connections. You can then define as many connection strings as you want and simply change the use key to whichever one is required. See http://www.devx.com/dotnet/Article/30910 for more information.

How do you deal with connection strings when deploying an ASP.NET site?

Right now our test and production databases are on the same server, but with different names. Deploying has meant editing Web.config to change all the connection strings for the correct database. A step which I forget all too frequently...
We've finally created a new database server for testing, and I'm moving the databases over... but now the server will be different and we'll still need to deal with connection string issues.
I was thinking of managing it via a hosts file, but the thought of switching that on my desktop machine whenever I need to test against production data seems cumbersome at best.
So I'm just wondering if there's a better way out there. Something that would build with a "production" web config for deployment would be ideal...
Use a Web Deployment Project and update the wdproj file (it's just an MSBuild file) with some post build tasks to output the correct .config file. I keep a web.config and web.release.config then use this in the wdproj file:
<Target Name="AfterBuild">
<Copy Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " SourceFiles="$(SourceWebPhysicalPath)\web.release.config" DestinationFiles="$(OutputPath)\web.config" />
<Delete Files="$(OutputPath)\web.release.config" />
</Target>
More information
A simpler solution some like is using configSource property of appSettings and connectionStrings and then never overwriting that file on the production server.
I usually have three separate web configs: one for my development machine, one for QA, and one for production. The development one connects to my local SQL database (which is firewalled from outside) and it is the default web.config. The others are named web-prod.config and web-qa.config. After publishing I delete the two that I don't need and rename the correct one to web.config. If I forget, the app breaks the first time it attempts to access the database, since the default config references one it can't get to.
Since IIS refuses to serve up a file named .config, I make sure they all end in .config instead of say web.config-prod or web.config-qa.
Here's another thing you can try:
Using SQL Server Configuration Manager, make a db Alias for your development database so that the web.config file can be the same on both your development box and the production server.
I create a database alias on each server to point to the database. I then use this alias in my web.config files. If I need to change which database the application points to, then I change the alias and not the web.config.
For SQL Server, go to SQL Server Configuration Manager > SQL Native Client Configuration > Aliases > Create New Alias.
You can do the same thing with Oracle with the tnsnames file.
have environment folders with separate configs for each environment
deploy out the correct one for the environment
I did this so often, I made the web.config on the production server read-only.
I've been in a few places now that store them in the registry.
There's probably more elaborate ways to do it now but a lot of code I've worked on with a 1.0/1.1 heritage store the strings in the registry.
The registry has a few advantages
It keeps people from deploying the code to the wrong places since machines not configured properly will lack the keys
It eliminates the problem wherein a developer will accidentally package a web.config file with the development connection strings in it (followed by a frantic phone call in the middle of the night wherein it is revealed that the late night sysadmin did not back up the previous web.config and the developer does not know or recall the production strings)
It limits the possibility of a hacker being able to get the connection string by fetching the web.config off of the machine. Plus the registry has more levels of security than the filesystem.
We drive our a deployments from our CI server. We usualy have a seperate file for each location and have the CI server switch to the appropriate config depending on the arguments passed ot it. All the file editing is done in NAnt scripts, so develops can run the sam build on their machine to get their own settings.
I'll put my connection strings in the machine.config on our QA and Production boxes. I'll keep them in the web.config on my dev box for flexibility, though. Then, I'll use a web deployment project to overwrite my dev connection strings with nothing (no connection strings) when deploying to QA. Therefore the QA site relies on the connection strings in machine.config. I still deploy to Production manually to make sure everything succeeds. I do this by manually copying everything from QA (except for web.config) to production.
This kind of task is exactly what build events are designed to address. Think of building as building for a specific target, any target specific configuration should be done there. (with the normal caveat that there are always some exceptions to the rule)
I've recently been leaning towards config manipulation on the continuous integration server. That's because we've had problems with multiple web.config, web.qa.config, web.production.config keeping the 95% of the file that should be the same in sync.
In a nutshell: there's only the one web.config in source control and it's the development configuration (debug friendly, local db, etc.). The build server does the compile, then a deploy to the canary site, then the package for release candidate.
We're using nant, so it's the .build file that has xmlpoke to set debug="false", alter connection strings, and whatever else needs to change in the canary copy and the packaging copy of the web.config.
The build machine's deploy is called "canary" because it's the first thing to die if there's a problem.

Resources