Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Securely encrypting / decrypting appsettings.json on server

How do I protect the encryption key used to encrypt sensitive data in my web application's appsettings.json?

I would like to protect sensitive data in my web application's config.

In ASP.NET MVC4 applications we did it like this:

  1. Sensitive data (e.g. password in a connection string) is not added directly to web.config (or web.prod.config etc.), instead a placeholder variable is written.
  2. At deployment time, our deployment service (Octopus) would retrieve sensitive data from its secure storage and overwrite the variable in the web.config.
  3. The deployment process would then encrypt sensitive sections of the web.config using aspnet_regiis.exe.

Now we are using ASP.NET Core the process we are following is a bit different.

  1. appsettings.json holds the placeholder variables for sensitive data, similar to how web.config worked before.
  2. Deployment process substitutes placeholders with sensitive data from it's secure store as before.
  3. Instead of using aspnet_regiis, I believe I need to:

    a) make my own custom tool to encrypt parts of the appsettings.json file.

    b) make a custom configuration provider that can decrypt (all / parts of) the appsettings.json

What I don't understand is how to protect the encryption key used for (a) and (b). The old way leveraged the server's machine key to encrypt the file.

The threat I am trying to mitigate is someone gaining access to the appsettings.json on the server and reading sensitive data out of it (e.g. database password etc.)

I am also intrested in alternative ways to mitigate this threat and/or other problems with this approach in general.

like image 232
Ergwun Avatar asked Dec 07 '17 04:12

Ergwun


4 Answers

If someone unauthorized gains access to the server, well, stealing the secrets - say, database connection strings, is just a small part of the problem (@Dmitry's answer).

Since you want a better control over the secret data or configuration, it is okay to slightly deviate from the usual appsettings.json-based approach.

You may take the secrets, asymmetrically encrypt them with the server's certificate, store them in a separate file (it could be another .json file for that matter) then read the file and decrypt the secrets at startup / on each web request. This way, the secrets are almost as safe as the server's certificate / private key.

Another option: symmetrically encrypt the secrets and feed the password to the web application at start-up so that it can decrypt the secrets. When the process hosting the web application restarts, you have to feed the password again (you can engage a separate machine to periodically feed it or so).

Also see Data Protection in ASP.NET Core, Data Protection samples.

Sometimes, long and cryptic passwords or simple obfuscation of an otherwise human-friendly password are sufficient. That is, just protecting against eavesdropping. Say, somebody sitting next to the admin won't be able to read and memorize a string of apparently random characters.

like image 137
turdus-merula Avatar answered Oct 27 '22 16:10

turdus-merula


It seems you're not interested in "ways" to do it, but in the recommended approach ASP.NET Core supports. While other answers here has mentioned the Azure KeyVault as a good storage for sensitive information, it's not the way to store it rather the actual storage. ASP.NET Core supports the notion of overridable configuration. That is, multiple configuration providers can be registered in the configuration system and the order they are registered in matters. Each registered one overrides settings from previous providers - those it has of course. In other words, if you have registered the standard JSON configuration provider and then also let's assume a database configuration provider, then those settings, which both providers have, will be getting the values defined by the later defined provider - the database provider. So in your situation, here what I'd suggest to do:

  1. Have all the default configuration providers registered as is.
  2. Register Azure Key Vault (or similar secret storage based provider) configuration provider in the end.
  3. Use certificate authentication to authenticate with Key Vault and read sensitive settings.

While this is not 1:1 mapping to what your current process is, it is inline with ASP.NET Core principles.

You can read more about ASP.NET Configuration at: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/index?tabs=basicconfiguration

Here you can read about Azure KeyVault configuration provider: https://docs.microsoft.com/en-us/aspnet/core/security/key-vault-configuration?tabs=aspnetcore2x

If certificate based auth is not an option for you, consider storing ClientId and ClientSecret used to connect to Azure Key Vault service in environment variables, and use an appropriate configuration provider (AddEnvironmentVariables() extension method will do it) to access those.

This setup will be really secure. Good luck!

like image 20
Artak Avatar answered Oct 27 '22 16:10

Artak


I am converting the comment into an answer :)

Even though you are not running on Azure, I would still recommend using Azure Key Vault for storing your secrets. For starters, it is very cheap (~$0.0159 / 10 000 operations) and secondly it can be accessed from anywhere, even outside Azure. Additionally, the secrets in Azure Key Vault can be versioned which is a nice feature to support multiple versions of a secret per environment (only for pre-production since Production should have a key vault of its own). The Key Vault NuGet package has operations to retrieve and add secrets within .NET Core. Here is a link to the documentation.

You can have an in-memory cache so a REST call (or Key Vault package method call) to Key Vault is made only at the start of your application (or when your cache expires), thereby preventing any further latencies. Third, this is the recommended approach by Microsoft.

Hope this helps.

like image 29
ThePretendProgrammer Avatar answered Oct 27 '22 14:10

ThePretendProgrammer


If you do not "trust" server - you can't protect "secrets" you store inside this server.

Explanation:

No matter what "secured" (=unsecured) scheme you invent - when application starts is must be able do "decrypt" secrets into some "usable" form.

This means that all "keys" (certs, etc) required to "decrypt" must exist on this server and be accessible to app (otherwise app can't start).

This means that some bad guy who access the server and app also can access all "keys" on it, and "decrypt" your secrets. May be by copying files, may be by decompiling you app, may be dumping you app memory - but it can.

There is no absolute protection.

like image 45
Dmitry Avatar answered Oct 27 '22 14:10

Dmitry