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>
orIOptionsSnapshot<T>
where T is that class that the section inappsettings.json
is bound to via theservices.Configure
method (E.g.MyAppSettings
). Alternatively, if you do not want to bind to a class, you could useIConfiguration
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
Cannot Access a Closed Stream of a Memorystream, How to Reopen
How to Check If a Socket Is Connected/Disconnected in C#
How to Submit Disabled Input in ASP.NET MVC
Error: the Entity Type Requires a Primary Key
How to Split Json String in C# and Store in Separate Variables
How to Provide Success Messages ASP.NET MVC
Linq to SQL Left Outer Join Using Lambda Syntax and Joining on 2 Columns (Composite Join Key)
Automapper - Map Using the Same Source and Destination Object Types
How to Delete All Files in an Azure File Storage Folder
.Net Core - How to Properly Kill Started Process
How to Close a File That Is Already Opened in a Directory
Using Recursion to Add Odd Numbers
How to Perform Join Between Multiple Tables in Linq Lambda
How to Authenticate a Webclient Request
How to Trim All Elements in a List
C# - How to Loop Through a Table to Update Each Row MySQL
Smtpexception: Unable to Read Data from the Transport Connection: Net_Io_Connectionclosed
How to Implement Async Task to Fetch Data from Database Using Async and Await