如何在ASP.Net Core中加密/解密appsettings.json的连接字符串?
ASP.NET Core Web API 连接字符串加密问题
我正在开发ASP.NET Core Web API,开发环境中直接在appsettings.json里用明文写连接字符串。现在要把API发布到生产服务器和外网(使用FortiWeb而非Azure),不能再明文保存凭据。我找了很多加密方法,大多依赖Azure Key Vault或用户机密,最后打算采用某篇文章的方案,但文章内容不完整。我已经创建了文中的类,但不知道怎么实际使用。这是我第一次从零开发API,完全不懂信息安全。
已完成的代码文件
appsettings.json
{ "ConnectionStrings": { "MyConnection": "Data Source=MyServerName;Initial Catalog=MyDb;Persist Security Info=True;User ID=MyUser;Password=MyPwd" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*" }
DecryptedConfiguration.cs
public class DecryptedConfiguration : ConfigurationProvider { public ICryptoTransform Decryptor; private ICryptoTransform Encryptor; internal DecryptedConfiguration(byte[] Key, byte[] IV) { Aes aes = Aes.Create(); Decryptor = aes.CreateDecryptor(Key, IV); Decryptor = aes.CreateDecryptor(Key, IV); } public override bool TryGet(string key, out string value) { if (base.TryGet(key, out value)) { byte[] decryptedBytes = Convert.FromBase64String(value); byte[] textBytes = Decryptor.TransformFinalBlock(decryptedBytes, 0, decryptedBytes.Length); value = Encoding.Unicode.GetString(textBytes); return true; } return false; } public override void Set(string key, string value) { byte[] textBytes = Encoding.Unicode.GetBytes(value); byte[] decryptedBytes = Decryptor.TransformFinalBlock(textBytes, 0, textBytes.Length); base.Set(key, Convert.ToBase64String(decryptedBytes)); } }
DecryptedConfigurationSource.cs
public class DecryptedConfigurationSource : IConfigurationSource { private byte[] Key; private byte[] IV; public DecryptedConfigurationSource(byte[] Key, byte[] IV) { this.Key = Key; this.IV = IV; } public IConfigurationProvider Build(IConfigurationBuilder builder) { return new DecryptedConfiguration(Key, IV); } }
Startup.cs(Configure方法片段)
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { ... Aes aes = Aes.Create(); byte[] key = aes.Key; byte[] iv = aes.IV; IConfigurationBuilder encryptingBuilder = new ConfigurationBuilder() .AddJsonFile("appsettings.json") .Add(new DecryptedConfigurationSource(key, iv)) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); IConfiguration cfg = encryptingBuilder.Build(); string ecryptedValue = cfg.GetValue<string>("ConnectionStrings:MyConnection"); }
完整使用步骤
1. 修复DecryptedConfiguration类的错误
你的代码存在两处关键错误,先修正:
- 构造函数重复赋值
Decryptor,需同时初始化加密器 Set方法误用解密器,应该用加密器处理明文
修正后的代码:
public class DecryptedConfiguration : ConfigurationProvider { private readonly ICryptoTransform _decryptor; private readonly ICryptoTransform _encryptor; internal DecryptedConfiguration(byte[] key, byte[] iv) { using Aes aes = Aes.Create(); _encryptor = aes.CreateEncryptor(key, iv); _decryptor = aes.CreateDecryptor(key, iv); } public override bool TryGet(string key, out string value) { if (base.TryGet(key, out value)) { byte[] encryptedBytes = Convert.FromBase64String(value); byte[] textBytes = _decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length); value = Encoding.Unicode.GetString(textBytes); return true; } return false; } public override void Set(string key, string value) { byte[] textBytes = Encoding.Unicode.GetBytes(value); byte[] encryptedBytes = _encryptor.TransformFinalBlock(textBytes, 0, textBytes.Length); base.Set(key, Convert.ToBase64String(encryptedBytes)); } }
2. 生成加密后的连接字符串
先把明文连接字符串加密,替换appsettings.json中的明文值。可以写一个临时工具生成加密值:
public static string EncryptConnectionString(string plainText, byte[] key, byte[] iv) { using Aes aes = Aes.Create(); using ICryptoTransform encryptor = aes.CreateEncryptor(key, iv); byte[] textBytes = Encoding.Unicode.GetBytes(plainText); byte[] encryptedBytes = encryptor.TransformFinalBlock(textBytes, 0, textBytes.Length); return Convert.ToBase64String(encryptedBytes); }
运行后得到加密字符串,更新appsettings.json:
"ConnectionStrings": { "MyConnection": "替换为加密后的Base64字符串" }
3. 正确集成配置到应用
不要在Configure方法中单独构建配置,应该在启动时将自定义配置源加入主配置体系,让整个应用能直接获取解密后的值。
.NET 6+ Program.cs示例
var builder = WebApplication.CreateBuilder(args); // 从环境变量加载密钥和IV(生产环境禁止硬编码) byte[] key = Convert.FromBase64String(Environment.GetEnvironmentVariable("AES_KEY")); byte[] iv = Convert.FromBase64String(Environment.GetEnvironmentVariable("AES_IV")); // 添加自定义配置源 builder.Configuration.Add(new DecryptedConfigurationSource(key, iv)); // 注册数据库上下文 builder.Services.AddDbContext<MyDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("MyConnection"))); var app = builder.Build(); // 中间件配置... app.Run();
.NET 5及以前 Startup.cs示例
public Startup(IConfiguration configuration, IWebHostEnvironment env) { var configBuilder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: false) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) .AddEnvironmentVariables(); // 加载密钥和IV byte[] key = Convert.FromBase64String(Environment.GetEnvironmentVariable("AES_KEY")); byte[] iv = Convert.FromBase64String(Environment.GetEnvironmentVariable("AES_IV")); configBuilder.Add(new DecryptedConfigurationSource(key, iv)); Configuration = configBuilder.Build(); } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddDbContext<MyDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("MyConnection"))); // 其他服务注册... }
4. 生产环境密钥管理注意事项
- 禁止硬编码密钥和IV,通过服务器环境变量、权限受限的本地文件或硬件安全模块(HSM)获取
- 确保生产服务器上只有应用进程能访问密钥存储位置
- 定期轮换密钥,避免密钥泄露导致所有加密数据暴露
内容的提问来源于stack exchange,提问作者Gabic
相关产品推荐
相关产品推荐

