How to Encrypt a Password Within Appsettings.Json for ASP.NET Core 2

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

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

How to set appsettings..json sensitive data into encrypted/hashed form using power shell and decrypt in c# code

With .net core you can use encrypted JSON by using Package EncryptedJsonConfiguration. In order to add the package you install it using NuGet manager or PowerShall :

Install-Package Miqo.EncryptedJsonConfiguration

Then in your Program.cs :

var key = Convert.FromBase64String(Environment.GetEnvironmentVariable("SECRET_SAUCE"));
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddEncryptedJsonFile("settings.ejson", key);
})
...

then in your startup file :

services.AddJsonEncryptedSettings<AppSettings>(_configuration);

For more info you should check : https://github.com/miqoas/Miqo.EncryptedJsonConfiguration

The most recommended way to create encrypted files is by using Kizuna command line tool.
Read more : https://github.com/miqoas/Kizuna

Encrypted configuration in ASP.NET Core

User secrets looks like a good solution for storing passwords, and, generally, application secrets, at least during development.

Check the official Microsoft documentation. You can also review this other SO question.

This is just a way to "hide" your secrets during development process and to avoid disclosing them into the source tree; the Secret Manager tool does not encrypt the stored secrets and should not be treated as a trusted store.

If you want to bring an encrypted appsettings.json to production, you can do so by building a custom configuration provider.

For example:

public class CustomConfigProvider : ConfigurationProvider, IConfigurationSource
{
public CustomConfigProvider()
{
}

public override void Load()
{
Data = UnencryptMyConfiguration();
}

private IDictionary<string, string> UnencryptMyConfiguration()
{
// do whatever you need to do here, for example load the file and unencrypt key by key
//Like:
var configValues = new Dictionary<string, string>
{
{"key1", "unencryptedValue1"},
{"key2", "unencryptedValue2"}
};
return configValues;
}

private IDictionary<string, string> CreateAndSaveDefaultValues(IDictionary<string, string> defaultDictionary)
{
var configValues = new Dictionary<string, string>
{
{"key1", "encryptedValue1"},
{"key2", "encryptedValue2"}
};
return configValues;
}

public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new CustomConfigProvider();
}
}

Define a static class for your extension method:

public static class CustomConfigProviderExtensions
{
public static IConfigurationBuilder AddEncryptedProvider(this IConfigurationBuilder builder)
{
return builder.Add(new CustomConfigProvider());
}
}

And then you can activate it:

// Set up configuration sources.
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEncryptedProvider()
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

How to avoid storing passwords or other sensitive data in appsettings.json

One common way is to store secrets in an external vault like e.g. Azure Key Vault. There is good documentation on how to do that on Microsoft docs here. It does require come local configuration like e.g. a certificate to provide credentials to the vault.

It will be merged with your other configuration parameters in the order that you self chose (by calling config.AddAzureKeyVault).

To avoid setting this up for local development environment you can use local secrets (dotnet user-secrets command and adding it to configuration the same way). There is documenation on the same URL about that as well. Be aware that it is no secure store, it's just a file on disk in plain text in practice.

P.S. It is possible to something that won't involve external provider. In the previous .Net ecosystem it was called web.config encryption. Basically you encrypted sections of web.config and the key was stored in windows with only given accounts who had access to it. It was quite a nightmarish experience, but no external provider was used. You can do something similar to that approach, but I don't know if there is something out of the box for .net core for that.

How to properly store and access encrypted values in .NET 5.0 appsettings.json file?

You're running into missing assembly errors because you're referencing the compiled library directly. The build system doesn't know about its dependencies (i.e. ProtectedData.dll), so it doesn't include them in your output folder when you build the application.

When you instead reference the library as a project, the build system can figure out everything that the library depends on by reading the project file, and include those dependencies in the output folder.

If you really need to reference the DLL directly for some reason, you need to copy its dependencies (generally the entire output folder from building it) into your application's directory.

It's much easier to just reference it as a project, unless there's some constraint preventing it. If it's not possible, deploying and referencing it as a NuGet package is an alternative that will ensure you automatically get all of the dependencies, but that comes with its own complexity.


On the topic of what you're trying to do with appsettings, this isn't going to work.

The methods you're calling pass through to the winapi CryptProtectData and CryptUnprotectData methods. They use a key derived from your login credentials, so it's not possible for data encrypted on one machine to be decrypted by another machine (or even another user on the same machine).

You can read up on alternative approaches for storing sensitive information here: https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-6.0&tabs=windows



Related Topics



Leave a reply



Submit