Warm tip: This article is reproduced from serverfault.com, please click

How do you encrypt a password within appsettings.json for ASP.net Core 2?

发布于 2018-01-08 22:56:38

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?

Questioner
Ryan Battistone
Viewed
0
2020-09-19 14:56:34

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.

  • The first is an 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.
  • The second is the decryption class that implements 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