I'd like to use my appsettings.json to store a "master password".
This master password would then be used to open up a private key (and its subsequent password store) generated by this excellent password store package: https://github.com/neosmart/SecureStore
The problem is, I can't think of any way to encrypt the master password. I know in .NET 4.5, it was possible to do the following:
1) Place your password into the web.config file
2) Run this script: aspnet_regiis.exe -pef appSettings "C:\myfolder"
3) Your password would end up being encrypted - but read securely by your program.
https://www.codeproject.com/Articles/599416/Encrypting-ASP-NET-Application-Settings
Am I going about this the right way or is there a better practice?
Remember do not store secrets in the main appsettings.json
that is in the web site and usually held in source control. Use a file provider to locate the file in some other location elsewhere on the server.
If you have access to Azure, you could store the secret in Azure Key Vault instead of appsettings.json
.
With that in mind, if your want to use a JSON file, you can use a bridge or a proxy class to handle the decryption of values.
First you will need a class to decrypt the values. For brevity, I won't go into the details of the decryption class here and will just assume that a class called SettingsDecryptor
has been written and implements an interface called ISettingsDecryptor
with a single method Decrypt which decrypts a string value.
The bridge class takes two constructor parameters.
IOptions<T>
or IOptionsSnapshot<T>
where T is that class that the section in appsettings.json
is bound to via the services.Configure
method (E.g. MyAppSettings
). Alternatively, if you do not want to bind to a class, you could use IConfiguration
instead and read directly from the configuration.ISettingsDecryptor
.In the bridge class, each property that requires decrypting should use the decryption class to decrypt the encrypted value in the configuration.
public class MyAppSettingsBridge : IAppSettings
{
private readonly IOptions<MyAppSettings> _appSettings;
private readonly ISettingsDecrypt _decryptor;
public MyAppSettingsBridge(IOptionsSnapshot<MyAppSettings> appSettings, ISettingsDecrypt decryptor) {
_appSettings = appSettings ?? throw new ArgumentNullException(nameof(appSettings));
_decryptor = decryptor ?? throw new ArgumentException(nameof(decryptor));
}
public string ApplicationName => _appSettings.Value.ApplicationName;
public string SqlConnectionSting => _decryptor.Decrypt(_appSettings.Value.Sql);
public string OracleConnectionSting => _decryptor.Decrypt(_appSettings.Value.Oracle);
}
The DI container should be set up something like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddOptions();
services.Configure<MyAppSettings>(Configuration.GetSection("MyAppSettings"));
services.AddSingleton(Configuration);
services.AddSingleton<ISettingsDecrypt, SettingsDecryptor>();
services.AddScoped<IAppSettings, MyAppSettingsBridge>();
}
The controller can then have a constructor that takes the bridge as an IAppSettings
to access the decrypted settings.
The above answer is a brief summary of the overall solution as there is quite a bit of code required.
The full detailed explanation can be seen at my blog post Hiding Secrets in appsettings.json
– Using a Bridge in your ASP.Net Core Configuration (Part 4) where I describe using a bridge pattern in detail. There is also a full example (including a decryption class) on Github at https://github.com/configureappio/ConfiguarationBridgeCrypto
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