Lee Wyncent
Lee Wyncent

Reputation: 29

how to encrypt appsettings.js string and still being usable?

I've done a login in postman with appsettings.js(attached below) and as the strings in appsettings.js is very sensitive and also being able to access easily, is there away i can make them secured or how i can i encrypt them?? sorry if i have any mistakes cause I'm very new to this.. thank you and please be understanding. Thank you

{
    "ConnectionStrings": {
        "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=HealthAPI;Trusted_Connection=True;MultipleActiveResultSets=true"
    },
    "Jwt": {
        "Site": "http://www.security.org",
        "SigningKey": "Paris Berlin Cairo Sydney Tokyo Beijing Rome London Athens",
        "ExpiryInMinutes": "60"
    },
    "Logging": {
        "LogLevel": {
            "Default": "Warning"
        }
    },
    "AllowedHosts": "*"
}

Upvotes: 1

Views: 645

Answers (1)

Brando Zhang
Brando Zhang

Reputation: 27962

According to your description, if you want to encrypt the appsettings.json section value, I suggest you could try to use asp.net core's DataProtection Dpapi to encrypt and decrypt the value.

Notice: For encrypt and decrypt the appsettings.json, we have a lot of solutions, I suggest you could also refer to this SO question.

You could create a extension class like below;

   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>();
                var protectedSection = new ProtectedConfigurationSection(dataProtectionProvider, section);

                var options = protectedSection.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);
            }
        }
    }

Then you could add these codes into your startup.cs ConfigureServices method to enable the data production:

        services.AddProtectedConfiguration();

To encrypt the appsettings.json you could try to create a controller like below:

[ApiController]
[Route("[controller]")]
 public class WeatherForecastController : ControllerBase
{
    private readonly IDataProtectionProvider _dataProtectionProvider;
    private readonly JWT _options;

    public WeatherForecastController(IDataProtectionProvider dataProtectionProvider, IOptions<JWT>  options)
    {
        _logger = logger;
        _IConfiguration = configuration;
        _dataProtectionProvider = dataProtectionProvider;
        _options = options.Value;
    }

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

}

Then you could call https://localhost/weatherforecast/encrypt?section=Jwt:ExpiryInMinutes&value=60 , https://localhost/weatherforecast/encrypt?section=Jwt:SigningKey&value=Paris Berlin Cairo Sydney Tokyo Beijing Rome London Athens to get three encrpted value and replace the encrtpted value with the default value in asp.net core json file like below:

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Warning"
    }
  },
  "AllowedHosts": "*",
  "Jwt": {
    "Site": "CfDJ8FPvxsDZrudHuLb0eHtPtst2lTrqwLJ3-6nCSj0e2wy6G2vtFZkGWPjlJGBKWJdCvJ0KIoq7konHIERH11_n4slwbzuzQNrZ4FC_oy9wMwj9hMIA4ueNNECHRl19yuiluvZ80XFjs2Uv0vm51pCJ7i0",
    "SigningKey": "CfDJ8FPvxsDZrudHuLb0eHtPtssQuzQVurrRyngNpmf1hJV_tUKW2F-7HnasihRtP19ZrGr8E7F6rMqCljaUcHN63VxZbB6JDqm4kvdLIEP3pNmzVexxpiajQYXf--ZnONu-ZYXWT_gcQcju5V9wY8UJSY8jE0f8y2G4kuzL27rL6P4v7U4w9DeXtu_mgUMej4f04w",
    "ExpiryInMinutes": "CfDJ8FPvxsDZrudHuLb0eHtPtsvMeMtrytasZ95VYSca8LgKbFXL4WIvBZ_dWGryT2g6ykW0kioQz9_i6IyS8DbX_81IgWXs4le-fix3yTc4D7BAJDM82D1Sp4P8FNNq4tBoHA"
  }
}

Then you could add services.ConfigureProtected method to register the configuration option value and directly get it in services by using DI.

Details, you could refer to below codes:

The startup.cs ConfigureServices methods:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddProtectedConfiguration();
        services.ConfigureProtected<JWT>(Configuration.GetSection("Jwt"));
        services.AddControllers();
      }

Usage:

[ApiController]
[Route("[controller]")]
 public class WeatherForecastController : ControllerBase
{
    private readonly IDataProtectionProvider _dataProtectionProvider;
    private readonly JWT _options;

    public WeatherForecastController(IDataProtectionProvider dataProtectionProvider, IOptions<JWT>  options)
    {
        _logger = logger;
        _IConfiguration = configuration;
        _dataProtectionProvider = dataProtectionProvider;
        _options = options.Value;
    }

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

       [HttpGet]
    public string Get()
    {
       var result = _options.SigningKey;

       return result;

     }

}

JWT Class:

public class JWT
{
    public string Site { get; set; }
    public string SigningKey { get; set; }
    public string ExpiryInMinutes { get; set; }
}

Result:

enter image description here

Upvotes: 1

Related Questions