简体   繁体   English

如何在 ASP.net Core 2 的 appsettings.json 中加密密码?

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

I'd like to use my appsettings.json to store a "master password".我想使用我的 appsettings.json 来存储“主密码”。

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然后,该主密码将用于打开由这个出色的密码存储包生成的私钥(及其后续的密码存储): 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:我知道在 .NET 4.5 中,可以执行以下操作:

1) Place your password into the web.config file 1) 将您的密码放入 web.config 文件中

2) Run this script: aspnet_regiis.exe -pef appSettings "C:\\myfolder" 2) 运行此脚本:aspnet_regiis.exe -pef appSettings "C:\\myfolder"

3) Your password would end up being encrypted - but read securely by your program. 3)您的密码最终会被加密 - 但您的程序可以安全地读取。

https://www.codeproject.com/Articles/599416/Encrypting-ASP-NET-Application-Settings 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.请记住,不要将机密存储在网站中的主要appsettings.json ,并且通常保存在源代码管理中。 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 .如果您有权访问 Azure,则可以将机密存储在Azure Key Vault而不是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.考虑到这一点,如果您想使用 JSON 文件,您可以使用网桥或代理类来处理值的解密。

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.为简洁起见,我不会在这里详细介绍解密类,只假设已经编写了一个名为SettingsDecryptor的类,并使用单个方法 Decrypt 实现了一个名为ISettingsDecryptor的接口,该接口解密字符串值。

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 (Eg MyAppSettings ).第一个是IOptions<T>IOptionsSnapshot<T> ,其中 T 是appsettings.json中的部分通过services.Configure方法(例如MyAppSettings )绑定到的那个类。 Alternatively, if you do not want to bind to a class, you could use IConfiguration instead and read directly from the configuration.或者,如果您不想绑定到类,则可以改用IConfiguration并直接从配置中读取。
  • The second is the decryption class that implements ISettingsDecryptor .第二个是实现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: DI 容器应该像这样设置:

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.然后控制器可以有一个构造函数,它将桥作为IAppSettings来访问解密的设置。

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.完整的详细解释可以在我的博客文章Hiding Secrets in appsettings.json – Using a Bridge in your ASP.Net Core Configuration(第 4 部分)中看到,其中我详细描述了使用桥接模式。 There is also a full example (including a decryption class) on Github at https://github.com/configureappio/ConfiguarationBridgeCryptohttps://github.com/configureappio/ConfiguarationBridgeCrypto上的 Github 上还有一个完整的示例(包括解密类)

The JSON configuration provider does not support encryption. JSON 配置提供程序不支持加密。 Currently, the only out of the box provider that does support encrypted configuration is Azure KeyVault.目前,唯一支持加密配置的开箱即用提供商是 Azure KeyVault。 You can use KeyVault whether or not your application is actually hosted on Azure, and although it's not free, the allowances are such that it would likely only cost pennies in most scenarios.无论您的应用程序是否实际托管在 Azure 上,您都可以使用 KeyVault,尽管它不是免费的,但在大多数情况下,它可能只需花费几美分。

That said, part of the beauty of Core is that it's completely modular.也就是说,Core 的部分优点在于它是完全模块化的。 You can always create your own configuration provider(s) and implement whatever you want.您始终可以创建自己的配置提供程序并实现您想要的任何内容。 For example, you could write a JSON provider that actually does support encryption, if that's how you want to go.例如,你可以写一个JSON提供商,实际上支持加密,如果这就是你想去的地方。

For ASP.NET Core the best solution is to do any transformations of the configuration values, like decryption or string replacements, when the application starts.对于 ASP.NET Core,最好的解决方案是在应用程序启动时对配置值进行任何转换,例如解密或字符串替换。 This is why configuration provider exists.这就是配置提供程序存在的原因。

The configuration providers can be chained.可以链接配置提供程序。 In the source code of the Microsoft.Extensions.Configuration there is class called ChainedConfigurationProvider that can be used as an example.在 Microsoft.Extensions.Configuration 的源代码中有一个名为ChainedConfigurationProvider 的类,可以用作示例。

public static IHostBuilder CreateHostBuilder(string[] args)
{
    return new HostBuilder()
    .ConfigureAppConfiguration((host, config) => {

        var jsonFile = new ConfigurationBuilder();
        jsonFile.AddJsonFile("appsettings.json");
        // the json file is the source for the new configuration provider.
        config.AddConfiguration(jsonFile.Build());
    });
}

If you are using Docker Swarm or Kubernetes you don't have to encrypt the password in the appsettings.json file.如果您使用 Docker Swarm 或 Kubernetes,则不必加密 appsettings.json 文件中的密码。 You can use the build-in Key-per-file Configuration Provider or custom configuration provider to read the password from a docker secret and map it to a configuration value.您可以使用内置的Key-per-file 配置提供程序或自定义配置提供程序从 docker 机密读取密码并将其映射到配置值。

On my blog post How to manage passwords in ASP.NET Core configuration files I explain in detail how to create a custom configuration provider that allows you to keep only the password as a secret and update the configuration string at runtime.在我的博客文章如何管理 ASP.NET Core 配置文件中的密码中,我详细解释了如何创建自定义配置提供程序,该提供程序允许您仅将密码作为机密并在运行时更新配置字符串。 Also the the full source code of this article is hosted on github.com/gabihodoroaga/blog-app-secrets .此外,本文的完整源代码托管在github.com/gabihodoroaga/blog-app-secrets 上

You could take a look at my Moonrise.StandardUtils.NetStd NuGet package.你可以看看我的Moonrise.StandardUtils.NetStd NuGet 包。 The Settings class has transparent en/decryption and is a much simpler way to access a JSON settings file - whether Application or User - in any .Net application. Settings 类具有透明的加密/解密,是在任何 .Net 应用程序中访问 JSON 设置文件(无论是应用程序还是用户)的更简单的方法。

Settings.Application.SettingsEncryptor = new DpApiSettingsEncryptor(DpApiSettingsEncryptor.ProtectionScope.Machine);
MyConfigClass config;
Settings.Application.Read("Configuration", ref config)

Anything individual or group of settings that has previously been encrypted will be decrypted.之前加密的任何个人或一组设置都将被解密。 You can encrypt a setting with;您可以使用以下方法加密设置;

Settings.Application.Write("ContainerStartup:FileProviders:BrandingConfig", secretValue, true);

Or use the EncryptAppSettings.exe that is bundled into Moonrise.Microsoft.EncryptedJsonConfiguration or the Moonrise.Samples NuGet packages - you'll find it in the package file/directory - well it's a way to get an .exe to folk.或者使用捆绑到Moonrise.Microsoft.EncryptedJsonConfigurationMoonrise.Samples NuGet 包中的 EncryptAppSettings.exe - 你会在包文件/目录中找到它 - 这是一种将 .exe 提供给大众的方法。

The Moonrise.Microsoft.EncryptedJsonConfiguration allows you to use the IConfigurationBuilder with .AddEncyptedJsonFile(...) which will then transparently decrypt any settings encrypted with the EncryptAppSettings.exe. Moonrise.Microsoft.EncryptedJsonConfiguration允许您将 IConfigurationBuilder 与 .AddEncyptedJsonFile(...) 一起使用,然后透明地解密使用 EncryptAppSettings.exe 加密的任何设置。

Here's a fragment of a partially encrypted appSettings.json这是部分加密的 appSettings.json 的片段

  "ContainerStartup": {
    "FileProviders": {
      "BrandingConfig": "[{ENC]{AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAsevacb5DdkaxvzOPPkLrdwQAAAACAAAAAAAQZgAAAAEAACAAAADITnvKp+Lnb5n6kPK7WyYuWFQLnbvbkOvgHBLBdIw2MAAAAAAOgAAAAAIAACAAAADqJZ0YUGC+jOEr4/6hgQ+8UdZ1ssbiEXXCjdhSV3teZ3AAAAAW4d8Z38JYNM1Dw45KquZYK+bTszYp/1wXt+LiYpiy2q88sOpQr5VpDFatgWar1aOePXA52RC6eZH1HFrYijqWTSEiffBqWzWZPPTXw1wkUVB5MLIjOq4bu33h+4Z23Vy+XaFsf6IFVl4ccM4fHpsRQAAAAAG5OP+nJQxzH3A7n3gnh8d2eAOFgLWzYCDgQon7NXHeEJcZezgxT+0npvIQ/kcYb1Xpwt7FiNtyJ2HZswL8MSg=]{ENC[{",
      "SearchingNotification": true,
      "UseBranding": false,
      "UseLocalModule": true,
      "UseLocalModuleEmbedded": true,
      "UseParentModules": true,
      "UseParentModulesEmbedded": false
    },

Instead of storing sensitive data in json files which you can't encrypt you can use Secret Manager tool.您可以使用 Secret Manager 工具,而不是将敏感数据存储在无法加密的 json 文件中。 Here is the full documentation .这是完整的文档

EDIT: from security perspective it is viable only for development purposes.编辑:从安全角度来看,它仅适用于开发目的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM