Scott Hanselman

Best practices for private config data and connection strings in configuration in ASP.NET and Azure

1月 6, '16 コメント [5] Posted in ASP.NET
Sponsored By

Image Copyright Shea Parikh / getcolorstock.com - used under licenseA reader emailed asking how to avoid accidentally checking in passwords and other sensitive data into GitHub or source control in general. I think it's fair to say that we've all done this once or twice - it's a rite of passage for developers old and new.

The simplest way to avoid checking in passwords and/or connection strings into source control is to (no joke) keep passwords and connection strings out of your source.

Sounds condescending or funny, but it's not, it's true. You can't check in what doesn't exist on disk.

That said, sometimes you just need to mark a file as "ignored," meaning it's not under source control. For some systems that involves externalizing configuration values that may be in shared config files with a bunch of non-sensitive config data.

ASP.NET 4.6 secrets and connection strings

Just to be clear, how "secret" something is is up to you. If it's truly cryptographically secret or something like a private key, you should be looking at data protection systems or a Key Vault like Azure Key Vault. Here we are talking about medium business impact web apps with API keys for 3rd party web APIs and connection strings that can live in memory for short periods. Be smart.

ASP.NET 4.6 has web.config XML files like this with name/value pairs.

<appSettings>      
<add key="name" value="someValue" />
<add key="name" value="someSECRETValue" />
</appSettings>

We don't want secrets in there! Instead, move them out like this:

<appSettings file="Web.SECRETS.config">      
<add key="name" value="someValue" />
</appSettings>

Then you just put another appSettings section in that web.secrets.config file and it gets merged at runtime.

NOTE: It's worth pointing out that the AppSettings technique also works for Console apps with an app.config.

Finally, be sure to add Web.secrets.config (or, even better, make it *.secrets and use a unique extension to identify your sensitive config.

This externalizing of config also works with the <connectionStrings> section, except you use the configSource attribute like this:

<connectionStrings configSource="secretConnectionStrings.config">
</connectionStrings>

Connection Strings/App Secrets in Azure

When you're deploying a web app to Azure (as often these apps are deployed from source/GitHub, etc) you should NEVER put your connection strings or appSettings in web.config or hard code them.

Instead, always use the Application Settings configuration section of Web Apps in Azure.

Application Settings and Secrets in Azure

These collection strings and name value pairs will automatically be made available transparently to your website so you don't need to change any ASP.NET code. Considered them to have more narrow scope than what's in web.config, and the system will merge the set automatically.

Additionally they are made available as Environment Variables, so you can Environment.GetEnvironmentVariable("APPSETTING_yourkey") as well. This works in any web framework, not just ASP.NET, so in PHP you just getenv('APPSETTING_yourkey") as you like.

The full list of database connection string types and the prepended string used for environment variables is below:

  • If you select “Sql Databases”, the prepended string is “SQLAZURECONNSTR_”
  • If you select “SQL Server” the prepended string is “SQLCONNSTR_”
  • If you select “MySQL” the prepended string is “MYSQLCONNSTR_”
  • If you select “Custom” the prepended string is “CUSTOMCONNSTR_”

ASP.NET 5

ASP.NET 5 has the concept of User Secrets or User-Level Secrets where the key/value pair does exist in a file BUT that file isn't in your project folder, it's stored in your OS user profile folder. That way there's no chance it'll get checked into source control. There's a secret manager (it's all beta so expect it to change) where you can set name/value pairs.

ASP.NET also has very flexible scoping rules in code. You can have an appSettings, then an environment-specific (dev, test, staging, prod) appSettings, then User Secrets, and then environment variables. All of this is done via code configuration and is, as I mentioned, deeply flexible. If you don't like it, you can change it.

var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

if (env.IsDevelopment())
{
// For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
builder.AddUserSecrets();
}

builder.AddEnvironmentVariables();
Configuration = builder.Build();

So, in conclusion:

  • Don't put private stuff in code.
    • Seems obvious, but...
  • Avoid putting private stuff in common config files
    • Externalize them AND ignore the externalized file so they don't get checked in
  • Consider using Environment Variables or User-level config options.
    • Keep sensitive config out of your project folder at development time

I'm sure I missed something. What are YOUR tips, Dear Reader?

Resources

Image Copyright Shea Parikh - used under license from http://getcolorstock.com


Sponsor: Big thanks to Infragistics for sponsoring the blog this week! Responsive web design on any browser, any platform and any device with Infragistics jQuery/HTML5 Controls.  Get super-charged performance with the world’s fastest HTML5 Grid - Download for free now!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web
2016年1月6日 7:20:14 UTC
So your saying that storing a connection string on the server in web.config is bad?
Mike
2016年1月6日 8:51:20 UTC
Only if it contains sensitive information i would assume...
Thomas
2016年1月6日 8:54:09 UTC
In previous ASP.NET versions you also did not store the secret file in the project folder but somewhere outside like a user directory which never gets checked into source control. The configSource attribute can point to any location.

@Mike: yes don't store your environment or secret data in web.config. This way you never have to transform your config when you promote your builds.
2016年1月6日 8:57:19 UTC
If you do add secrets into any web.config file (Even a web.secrets.config file as in the example Scott gave), don't forget to encrypt it. More info here.
2016年1月6日 9:13:35 UTC
He's saying that you should keep your secrets (user names, passwords, connection strings, etc.) hidden. Which means not checking it into source control (tfs, github, svn, etc.).

Of course you will need them in test or prod and everything in between. But those secrets should live on the server, which is hopefully better secured than your source control. So you set them when you deploy to the server (only the first time, then just don't override the settings unless you really, really need to). That way, if you accidentally create a public instead of a private github repo, no bad guy can see those secrets.

You'll need access during development, of course. But those configs should be passed around through a different way than storing them generally in your source control. Maybe even a different access code for each developer. That way you can monitor who does what.
KenBonny
名前
メールアドレス gravatarアイコンを表示)
ホームページ
 
コメント(一部のHTMLは使用可能です:a@href@title, b, blockquote@cite, em, i, li, ol, pre, strike, strong, sub, super, u, ul@はattributeつまり属性を意味します。例えば、<a href="" title=""> or <blockquote cite="Scott">.などを使用することができます。)
コメントのプレビューを同時に表示

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.