How do you secure sensitive data in configuration files?

4 minintermediatesecuritysecretsconfiguration

Quick Answer

Never commit secrets (connection strings, API keys) in plain text in source or config. In development use the Secret Manager (`dotnet user-secrets`); in production use a secure store such as Azure Key Vault, AWS Secrets Manager, or environment variables injected by the platform, accessed through the configuration system. Rotate secrets regularly and restrict access with least privilege.

Detailed Answer

Never store secrets in plain text! Use secure storage mechanisms.

Methods in .NET Core:

  1. User Secrets (Development Only):
dotnet user-secrets init
dotnet user-secrets set "ConnectionStrings:DefaultConnection" "Server=..."
dotnet user-secrets set "ApiKeys:GoogleMaps" "AIza..."
// Access in code
public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }
    
    public IConfiguration Configuration { get; }
    
    public void ConfigureServices(IServiceCollection services)
    {
        var connectionString = Configuration["ConnectionStrings:DefaultConnection"];
        var apiKey = Configuration["ApiKeys:GoogleMaps"];
    }
}
  1. Azure Key Vault (Production):
dotnet add package Azure.Extensions.AspNetCore.Configuration.Secrets
dotnet add package Azure.Identity
// Program.cs
public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((context, config) =>
        {
            if (context.HostingEnvironment.IsProduction())
            {
                var builtConfig = config.Build();
                var keyVaultEndpoint = builtConfig["KeyVault:Endpoint"];
                
                config.AddAzureKeyVault(
                    new Uri(keyVaultEndpoint),
                    new DefaultAzureCredential());
            }
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup();
        });
  1. Environment Variables:
// launchSettings.json (Development)
{
  "profiles": {
    "MyApp": {
      "environmentVariables": {
        "ConnectionStrings__DefaultConnection": "Server=...",
        "ApiKeys__GoogleMaps": "AIza..."
      }
    }
  }
}

// Access in code
var connectionString = Configuration["ConnectionStrings:DefaultConnection"];
  1. Encrypted Configuration:
using System.Security.Cryptography;

public class EncryptedConfigurationProvider : ConfigurationProvider
{
    private readonly string _encryptedFilePath;
    private readonly byte[] _key;
    
    public override void Load()
    {
        var encryptedData = File.ReadAllBytes(_encryptedFilePath);
        var decryptedData = Decrypt(encryptedData, _key);
        
        // Parse and load configuration
        Data = ParseConfiguration(decryptedData);
    }
    
    private byte[] Decrypt(byte[] data, byte[] key)
    {
        using var aes = Aes.Create();
        aes.Key = key;
        // Decryption logic
        return decryptedData;
    }
}
  1. AWS Secrets Manager:
dotnet add package AWSSDK.SecretsManager
dotnet add package Amazon.Extensions.Configuration.SystemsManager
public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((context, config) =>
        {
            config.AddSystemsManager("/myapp/");
        });
  1. Protected Configuration Sections:
public class SecureSettings
{
    public string ApiKey { get; set; }
    public string ConnectionString { get; set; }
}

// Startup.cs
services.Configure(Configuration.GetSection("SecureSettings"));

// Usage with IOptions
public class MyService
{
    private readonly SecureSettings _settings;
    
    public MyService(IOptions settings)
    {
        _settings = settings.Value;
    }
}

Best Practices:

  • Never commit secrets to source control
  • Use different secrets for each environment
  • Rotate secrets regularly
  • Audit secret access
  • Use managed identities when possible