3

I know there are plenty of questions here already about this topic (I've read through as many as I could find), but I haven't yet been able to figure out how best to satisfy my particular criteria. Here are the goals:

  1. The ASP.NET application will run on a few different web servers, including localhost workstations for development. This means encrypting web.config using a machine key is out. Each "type" or environment of web server (dev, test, prod) has its own corresponding database (dev, test, prod). We want to separate these connection strings so that a developer working on the "dev" code is not able to see any "prod" connection string passwords, nor allow these production passwords to ever get deployed to the wrong server or committed to SVN.

  2. The application will should be able to decide which connection string to attempt to use based on the server name (using a switch statement). For example, "localhost" and "dev.example.com" will should know to use the DevDatabaseConnectionString, "test.example.com" will use the TestDatabaseConnectionString, and "www.example.com" will use the ProdDatabaseConnectionString, for example. The reason for this is to limit the chance for any deployment accidents, where the wrong type of web server connects to the wrong database.

  3. Ideally, the exact same executables and web.config should be able to run on any of these environments, without needing to tailor or configure each environment separately every time that we deploy (something that seems like it would be easy to forget/mess up one day during a deployment, which is why we moved away from having just one connectionstring that has to be changed on each target). Deployment is currently accomplished via FTP. Update: Using "build events " and revising our deployment procedures is probably not a bad idea.

  4. We will not have command-line access to the production web server. This means using aspnet_regiis.exe to encrypt the web.config is out. Update: We can do this programmatically so this point is moot.

  5. We would prefer to not have to recompile the application whenever a password changes, so using web.config (or db.config or whatever) seems to make the most sense.

  6. A developer should not be able to get to the production database password. If a developer checks the source code out onto their localhost laptop (which would determine that it should be using the DevDatabaseConnectionString, remember?) and the laptop gets lost or stolen, it should not be possible to get at the other connection strings. Thus, having a single RSA private key to un-encrypt all three passwords cannot be considered. (Contrary to #3 above, it does seem like we'd need to have three separate key files if we went this route; these could be installed once per machine, and should the wrong key file get deployed to the wrong server, the worst that should happen is that the app can't decrypt anything---and not allow the wrong host to access the wrong database!)

  7. UPDATE/ADDENDUM: The app has several separate web-facing components to it: a classic ASMX Web Services project, an ASPX Web Forms app, and a newer MVC app. In order to not go mad having the same connection string configured in each of these separate projects for each separate environment, it would be nice to have this only appear in one place. (Probably in our DAL class library or in a single linked config file.)

I know this is probably a subjective question (asking for a "best" way to do something), but given the criteria I've mentioned, I'm hoping that a single best answer will indeed arise.

Thank you!

Funka
  • 4,258
  • 2
  • 24
  • 27

3 Answers3

3

Integrated authentication/windows authentication is a good option. No passwords, at least none that need be stored in the web.config. In fact, it's the option I prefer unless admins have explicity taken it away from me.

Personally, for anything that varies by machine (which isn't just connection string) I put in a external reference from the web.config using this technique: http://www.devx.com/vb2themax/Tip/18880

When I throw code over the fence to the production server admin, he gets a new web.config, but doesn't get the external file-- he uses the one he had earlier.

MatthewMartin
  • 32,326
  • 33
  • 105
  • 164
  • using integrated/windows auth would simplify this, but does that not shift somewhat of the burden to the system/machine administrators (setting up the users/credentials/domain etc) away from the programmers? If someone wants to work from home on their own machine, having a connection string to the dev database allows them to get right to work and not worry about this aspect. – Funka Jun 14 '10 at 21:39
  • I put a lot of thought into this once when I was trying to figure out how to make an ASP.NET app (a blog like thing) as easy to deploy for people for whom it was unreasonable to ask to know even basic admin tasks. I decided only a file based database would be easy enough. dasBlog (which uses solely XML files as a db) is a good example of this. But even then, after removing the need for a config string, password or user ID, you still have to make the files writable and give NTFS write permissions to the IIS account. For ultimate simplicity, find a DB+webserver with no security what-so-ever. – MatthewMartin Jun 14 '10 at 21:50
  • Using a separate .config file is certainly a good idea and one I'm looking into. Using a different key name in each (tied to a particular server name, as we're currently already doing) could eliminate the possibility for the wrong file to be used in the wrong environment. We would probably want to not have this file checked into SVN to minimize someone grabbing the wrong "version" of this file, and of course to not expose the passwords to it either. – Funka Jun 14 '10 at 22:16
  • Running a site/db with no security whatsoever would _certainly_ be the ultimate form of simplicity; unfortunately, we need our lovely SQL Server and need to allow only the right people to be looking around in it! – Funka Jun 14 '10 at 22:19
1
  1. you can have multiple web servers with the same encrypted key. you would do this in machine config just ensure each key is the same.

..

one common practice, is to store first connection string encrypted somewhere on the machine such as registry. after the server connects using that string, it will than retrieve all other connection strings which would be managed in the database (also encrypted). that way connection strings can be dynamically generated based on authorization requirements (requestor, application being used, etc) for example the same tables can be accessed with different rights depending on context and users/groups

i believe this scenario addresses all (or most?) of your points..

Sonic Soul
  • 23,855
  • 37
  • 130
  • 196
  • Regarding making the machine.config the same on everyone's machine (servers and dev workstations), would this not then allow a developer to decrypt the production database connection string? I am hoping to achieve a separation whereby this would _not_ be possible. (Worst-case scenario, a developer laptop is stolen and can be used to gain access to this!) – Funka Jun 14 '10 at 21:29
  • no.. if you can't break the encryption on one machine, why would you be able to do the same thing on another machine? it doesn't make it any less secure to have the same key on all web servers. – Sonic Soul Jun 15 '10 at 04:17
  • If we give the developers the same machine key as is used on the production webserver, they (or whoever steals their computer) don't need to "break" anything. We've just given them the key! – Funka Jun 15 '10 at 22:01
  • how does having a different key on each web server solve the scenario you've just described? – Sonic Soul Jun 15 '10 at 22:22
  • I have edited my question and clarified #1. The point was to provide some background details in order to arrive at a good solution, not to presume that such a solution might have anything to do with a machine.config file or not. (And hence why I'm asking!) Thx! – Funka Jun 16 '10 at 18:57
1

(First, Wow, I think 2 or 3 "quick paragraphs" turned out a little longer than I'd thought! Here I go...)

I've come to the conclusion (perhaps you'll disagree with me on this) that the ability to "protect" the web.config whilst on the server (or by using aspnet_iisreg) has only limited benefit, and is perhaps maybe not such a good thing as it may possibly give a false sense of security. My theory is that if someone is able to obtain access to the filesystem in order to read this web.config in the first place, then they also probably have access to create their own simple ASPX file which can "unprotect" it and reveal its secrets to them. But if unauthorized people are trouncing around in your filesystem—well… then you have bigger problems at hand, so my whole concern is now moot! 1

I also realize that there isn’t a foolproof way to securely hide passwords within a DLL either, as they can eventually be disassembled and discovered, perhaps by using something like ILDASM. 2 An additional measure of security obscurity can be obtained by obfuscating and encrypting your binaries, such as by using Dotfuscator, but this isn’t to be considered “secure.” And again, if someone has read access (and likely write access too) to your binaries and filesystem, you’ve again got bigger problems at hand methinks.

To address the concerns I mentioned about not wanting the passwords to live on developer laptops or in SVN: solving this through a separate “.config” file that does not live in SVN is (now!) the blindingly obvious choice. Web.config can live happily in source control, while just the secret parts do not. However---and this is why I’m following up on my own question with such a long response---there are still a few extra steps I’ve taken to try and make this if not any more secure, then at least a little bit more obscure.

Connection strings we want to try to keep secret (those other than the development passwords) won’t ever live as plain text in any files. These are now encrypted first with a secret (symmetric) key---using, of course, the new ridiculous Encryptinator(TM)! utility built just for this purpose---before they get placed in a copy of a “db.config” file. The db.config is then just uploaded only to its respective server. The secret key is compiled directly into the DAL’s dll, which itself would then (ideally!) be further obfuscated and encrypted with something like Dotfuscator. This will hopefully keep out any casual curiosity at the least.

I’m not going to worry much at all about the symmetric "DbKey" living in the DLLs or SVN or on developer laptops. It’s the passwords themselves I’ll keep out. We do still need to have a “db.config” file in the project in order to develop and debug, but it has all fake passwords in it except for development ones. Actual servers have actual copies with just their own proper secrets. The db.config file is typically reverted (using SVN) to a safe state and never stored with real secrets in our subversion repository.

With all this said, I know it’s not a perfect solution (does one exist?), and one that does still require a post-it note with some deployment reminders on it, but it does seem like enough of an extra layer of hassle that might very well keep out all but the most clever and determined attackers. I’ve had to resign myself to "good-enough" security which isn’t perfect, but does let me get back to work after feeling alright about having given it the ol’ "College Try!"


1. Per my comment on June 15 here http://www.dotnetcurry.com/ShowArticle.aspx?ID=185 - let me know if I'm off-base! -and some more good commentary here Encrypting connection strings so other devs can't decrypt, but app still has access here Is encrypting web.config pointless? and here Encrypting web.config using Protected Configuration pointless?

2. Good discussion and food for thought on a different subject but very-related concepts here: Securely store a password in program code? - what really hit home is the Pidgin FAQ linked from the selected answer: If someone has your program, they can get to its secrets.

Community
  • 1
  • 1
Funka
  • 4,258
  • 2
  • 24
  • 27