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:
web.config
(or web.prod.config
etc.), instead a placeholder variable is written.web.config
.aspnet_regiis.exe
.Now we are using ASP.NET Core the process we are following is a bit different.
appsettings.json
holds the placeholder variables for sensitive data,
similar to how web.config worked before.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.
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.
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:
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!
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With