[英]How to encrypt/decrypt connection string in appsettings.json?
我正在开发一个 ASP.Net Core Web API ,而在开发环境中,我们只需在appsettings.json
文件中以纯文本形式编写连接字符串。 但是现在我们要将此 API 发布到我们的生产服务器和 web(我们将使用 FortiWeb 发布 API,而不是 Azure),所以我们不能再拥有纯文本的用户凭据。
我一直在寻找保护/加密连接字符串的方法,但大多数解决方案都使用 Azure Key Vault 或用户机密。 我决定按照这篇文章来加密和解密appsettings.json
信息,但它有点不完整。 我设法创建了文章中描述的类,但我被卡住了,不知道如何使用它。 这是我第一次完全从头开始开发 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
class 上:
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
class 上:
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
class 上:
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");
}
作为一个简短的提示,我可以建议将值存储在环境变量中。 这比将它们直接存储在文本文件中更安全一些,因为访问环境变量需要比读取文件更高的权限。 对于许多公司来说,如果 azure 密钥保管库或 aws 机密管理器无法使用,这已经足够了。 如果您将应用程序托管为 docker 容器或在 VM 上运行,则可以同时使用环境变量。 这里有一些关于易于使用的解决方案的文章,尽管生产文章建议使用 azure 密钥库https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-6.0 &tabs=窗口
作为替代方案,您可以考虑使用文章中描述的 Secret manager 提供程序。
我不建议按照文章的建议进行,因为这涉及将加密密钥永久存储在某处(文章提到您不应该调用 Aes aes = Aes.Create(); 因为每次调用它都会生成新密钥,您需要一个永久的一)。 但是要确保它的安全,您必须从诸如 azure 密钥库之类的安全的东西中加载它,如果您在代码中拥有它,那么有人可以下载您的程序集,反编译它,访问存储的密钥并可以自行解密您的所有秘密。 如果我的理解是正确的,那么文章中提出的解决方案是“通过默默无闻的安全”而不是实际的解决方案 - 它只会使访问秘密变得更加困难,但仍然可以完全管理,就像您将秘密放在 appsettings.json 中一样。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.