简体   繁体   English

如何加密/解密 appsettings.json 中的连接字符串?

[英]How to encrypt/decrypt connection string in appsettings.json?

I am developing an ASP.Net Core Web API and while on dev environment we just write our connection string in plain text on the appsettings.json file.我正在开发一个 ASP.Net Core Web API ,而在开发环境中,我们只需在appsettings.json文件中以纯文本形式编写连接字符串。 But now we are going to publish this API to our production server and to web (we will use FortiWeb to publish the API, not Azure), so we can't have the user credentials in plain text anymore.但是现在我们要将此 API 发布到我们的生产服务器和 web(我们将使用 FortiWeb 发布 API,而不是 Azure),所以我们不能再拥有纯文本的用户凭据。

I've been searching for methods to protect/encrypt my connection string, but most solutions use Azure Key Vault ou user secrets.我一直在寻找保护/加密连接字符串的方法,但大多数解决方案都使用 Azure Key Vault 或用户机密。 I decided to follow this article to encrypt and decrypt the appsettings.json info, but it's kinda incomplete.我决定按照这篇文章来加密和解密appsettings.json信息,但它有点不完整。 I managed to create the classes described on the article, but I'm stuck and have no idea about how to use it.我设法创建了文章中描述的类,但我被卡住了,不知道如何使用它。 This is the first time I'm developing an API completely from scratch, and I'm totally newbie on info security.这是我第一次完全从头开始开发 API,而且我完全是信息安全的新手。

Here's what I have so far:这是我到目前为止所拥有的:

On appsettings.json file: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": "*"
}

On DecryptedConfiguration.cs class: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));
    }
}

On DecryptedConfigurationSource.cs class: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);
    }
}

On Startup.cs class: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");
}

Just as a short hint, I could recommend storing the values in environment variables.作为一个简短的提示,我可以建议将值存储在环境变量中。 This is a bit more secure than storing them plainly in text files as accessing environment variables requires higher priviledges than reading a file.这比将它们直接存储在文本文件中更安全一些,因为访问环境变量需要比读取文件更高的权限。 For many companies this was enough solution if azure key vault or aws secret manager could not be used.对于许多公司来说,如果 azure 密钥保管库或 aws 机密管理器无法使用,这已经足够了。 Environment variables you can use both if you host your app as docker container or running on VM.如果您将应用程序托管为 docker 容器或在 VM 上运行,则可以同时使用环境变量。 Here you have some article on easy to use solution, though the article for production recommends using azure key vault https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-6.0&tabs=windows这里有一些关于易于使用的解决方案的文章,尽管生产文章建议使用 azure 密钥库https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-6.0 &tabs=窗口

As an alternative you may consider using Secret manager provider described in the article.作为替代方案,您可以考虑使用文章中描述的 Secret manager 提供程序。

I would not recommend going by what article suggest because this involves storing somewhere permanently the encryption key (article mentiones you should not call Aes aes = Aes.Create(); because every time it is called new key is generated, you would need a permanent one).我不建议按照文章的建议进行,因为这涉及将加密密钥永久存储在某处(文章提到您不应该调用 Aes aes = Aes.Create(); 因为每次调用它都会生成新密钥,您需要一个永久的一)。 But to have it secured you have to load it from something secure like azure key vault, if you have it in code, someone could just dowlonad your assembly, decompile it, access the stored key and can on its own decrypt all your secrets.但是要确保它的安全,您必须从诸如 azure 密钥库之类的安全的东西中加载它,如果您在代码中拥有它,那么有人可以下载您的程序集,反编译它,访问存储的密钥并可以自行解密您的所有秘密。 If my understanding is correct the solution proposed in the article is "security through obscurity" rather than actual solution - it only makes the access to secrets a bit harder but still fully managable as if you place your secrets in the appsettings.json.如果我的理解是正确的,那么文章中提出的解决方案是“通过默默无闻的安全”而不是实际的解决方案 - 它只会使访问秘密变得更加困难,但仍然可以完全管理,就像您将秘密放在 appsettings.json 中一样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM