tag renderpartialasync pages net asp asp.net-mvc asp.net-core asp.net-core-mvc .net-core

asp.net-mvc - renderpartialasync - razor partial



ConfiguraciĆ³n cifrada en ASP.NET Core (4)

Con web.config desapareciendo, ¿cuál es la forma preferida de almacenar información confidencial (contraseñas, tokens) en las configuraciones de una aplicación web creada con ASP.NET Core?

¿Hay alguna forma de obtener automáticamente secciones de configuración cifradas en appsetttings.json ?


Estoy de acuerdo con @CoderSteve en que escribir un proveedor completamente nuevo es demasiado trabajo. Tampoco se basa en la arquitectura JSON estándar existente. Aquí hay una solución que se me ocurre a partir de la arquitectura estándar de JSON, utiliza las bibliotecas de cifrado de .Net Core preferidas y es muy fácil de usar para la ID.

public static class IServiceCollectionExtensions { public static IServiceCollection AddProtectedConfiguration(this IServiceCollection services) { services .AddDataProtection() .PersistKeysToFileSystem(new DirectoryInfo(@"c:/keys")) .ProtectKeysWithDpapi(); return services; } public static IServiceCollection ConfigureProtected<TOptions>(this IServiceCollection services, IConfigurationSection section) where TOptions: class, new() { return services.AddSingleton(provider => { var dataProtectionProvider = provider.GetRequiredService<IDataProtectionProvider>(); section = new ProtectedConfigurationSection(dataProtectionProvider, section); var options = section.Get<TOptions>(); return Options.Create(options); }); } private class ProtectedConfigurationSection : IConfigurationSection { private readonly IDataProtectionProvider _dataProtectionProvider; private readonly IConfigurationSection _section; private readonly Lazy<IDataProtector> _protector; public ProtectedConfigurationSection( IDataProtectionProvider dataProtectionProvider, IConfigurationSection section) { _dataProtectionProvider = dataProtectionProvider; _section = section; _protector = new Lazy<IDataProtector>(() => dataProtectionProvider.CreateProtector(section.Path)); } public IConfigurationSection GetSection(string key) { return new ProtectedConfigurationSection(_dataProtectionProvider, _section.GetSection(key)); } public IEnumerable<IConfigurationSection> GetChildren() { return _section.GetChildren() .Select(x => new ProtectedConfigurationSection(_dataProtectionProvider, x)); } public IChangeToken GetReloadToken() { return _section.GetReloadToken(); } public string this[string key] { get => GetProtectedValue(_section[key]); set => _section[key] = _protector.Value.Protect(value); } public string Key => _section.Key; public string Path => _section.Path; public string Value { get => GetProtectedValue(_section.Value); set => _section.Value = _protector.Value.Protect(value); } private string GetProtectedValue(string value) { if (value == null) return null; return _protector.Value.Unprotect(value); } } }

Conecta tus secciones de configuración protegidas de esta manera:

public void ConfigureServices(IServiceCollection services) { services.AddMvc(); // Configure normal config settings services.Configure<MySettings>(Configuration.GetSection("MySettings")); // Configure protected config settings services.AddProtectedConfiguration(); services.ConfigureProtected<MyProtectedSettings>(Configuration.GetSection("MyProtectedSettings")); }

Puede crear fácilmente valores cifrados para sus archivos de configuración utilizando un controlador como este:

[Route("encrypt"), HttpGet, HttpPost] public string Encrypt(string section, string value) { var protector = _dataProtectionProvider.CreateProtector(section); return protector.Protect(value); }

Uso: http://localhost/cryptography/encrypt?section=SectionName:KeyName&value=PlainTextValue


Los secretos de usuario parecen ser una buena solución para almacenar contraseñas y, en general, secretos de aplicaciones, al menos durante el desarrollo .

Revisa este article o this . También puede consultar this otra pregunta SO.

Esta es solo una forma de "ocultar" sus secretos durante el proceso de desarrollo y evitar que se revelen en el árbol de origen; La herramienta Secret Manager no encripta los secretos almacenados y no debe ser tratada como un almacén confiable.

Si desea traer un appsettings.json cifrado a producción, no hay límite al respecto. Puede construir su proveedor de configuración personalizada. Mira this

Por ejemplo:

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(); } }

Defina una clase estática para su método de extensión:

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

Y luego puedes activarlo:

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


No quería escribir un proveedor personalizado, demasiado trabajo. Solo quería acceder a JsonConfigurationProvider, así que descubrí una manera que funcione para mí, espero que ayude a alguien.

public class JsonConfigurationProvider2 : JsonConfigurationProvider { public JsonConfigurationProvider2(JsonConfigurationSource2 source) : base(source) { } public override void Load(Stream stream) { // Let the base class do the heavy lifting. base.Load(stream); // Do decryption here, you can tap into the Data property like so: Data["abc:password"] = MyEncryptionLibrary.Decrypt(Data["abc:password"]); // But you have to make your own MyEncryptionLibrary, not included here } } public class JsonConfigurationSource2 : JsonConfigurationSource { public override IConfigurationProvider Build(IConfigurationBuilder builder) { EnsureDefaults(builder); return new JsonConfigurationProvider2(this); } } public static class JsonConfigurationExtensions2 { public static IConfigurationBuilder AddJsonFile2(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange) { if (builder == null) { throw new ArgumentNullException(nameof(builder)); } if (string.IsNullOrEmpty(path)) { throw new ArgumentException("File path must be a non-empty string."); } var source = new JsonConfigurationSource2 { FileProvider = null, Path = path, Optional = optional, ReloadOnChange = reloadOnChange }; source.ResolveFileProvider(); builder.Add(source); return builder; } }


public static IServiceCollection ConfigureProtected<TOptions>(this IServiceCollection services, IConfigurationSection section) where TOptions: class, new() { return services.AddSingleton(provider => { var dataProtectionProvider = provider.GetRequiredService<IDataProtectionProvider>(); var protectedSection = new ProtectedConfigurationSection(dataProtectionProvider, section); var options = protectedSection.Get<TOptions>(); return Options.Create(options); }); }

Este metodo es correcto