【问题标题】:Storing SQL Connection details - how can I encrypt per-user safely?存储 SQL 连接详细信息 - 如何安全地加密每个用户?
【发布时间】:2009-07-01 20:36:32
【问题描述】:

我有一个应用程序连接到多个 SQL Server 以进行监控和其他任务。目前,我只支持受信任的身份验证,因为我不必存储任何敏感信息。我想添加使用 SQL 身份验证(用户名/密码)的功能。

在会话之间存储这些敏感数据的最佳方法是什么?是否有可供我使用的用户专用证书或加密密钥?使用每个用户随机生成的注册表项来加密此信息是否足够安全?如果有一种方法可以让我使用密钥(或创建密钥并存储它)以使计算机上的其他用户无法访问它,那就太理想了。

我了解加密,所以我不是在寻找教程 - 我在寻找最安全的方法来保护我的应用程序的一个用户的配置数据免受其他用户的影响。

【问题讨论】:

    标签: .net configuration encryption


    【解决方案1】:

    使用Data Protection API (aka. DPAPI)。每次使用都有一个受其密码保护的密钥。您将密码/连接字符串存储在 .config 文件中,.Net 框架具有使用机器密钥、用户密钥或 RSA 密钥加密/解密配置部分的方法。不要重新发明轮子来做你自己的自定义方案。使用注册表项绝对是个坏主意。安全性来自秘密,而不是访问保护:它必须依赖于用户提供秘密(登录时的密码),而不是无法访问的注册表项。

    How To: Encrypt Configuration Sections in ASP.NET 2.0 Using DPAPI

    【讨论】:

    • 看来我可以使用 DPAPI,并将密钥存储在用户存储中,因此机器上的任何其他用户都无法访问它。这看起来正是我想要做的 - 谢谢!
    • 我最终在这里使用了相同的修改版本:obviex.com/samples/dpapi.aspx
    【解决方案2】:

    正如 Remus 所说,使用 DPAPI。但不要使用 PInvoke 方法(如您的链接示例中),而是使用 ProtectedData 类。那是围绕 DPAPI 的托管包装器。很多示例都使用 PInvoke 来访问 DPAPI,因为在 .Net 2.0 之前没有托管方式来执行此操作。 DataProtectionScope 类使您能够加密/解密当前用户或机器的数据。

    【讨论】:

    • 注意 - 我也不喜欢调用,很高兴知道它周围有一个托管包装器。
    【解决方案3】:

    正如 Remus 指出的,有可用的用户/机器级加密。

    我通常对此类事情感到害怕,因为这些数据很容易丢失。

    如果我是你,我会推出自己的系统。使用应用程序中硬编码的密钥加密连接字符串,转换为 Base64,并将生成的加密连接字符串存储在注册表中。


    以下函数接受一个字符串,使用 AES-256 和指定的密钥对其进行加密,并将结果作为 base64 的结果返回为可打印的字符串:

    示例用法:

    String connectionString = EncryptString(
         "Provider=SQLOLEDB;Data Source=Lithium;User Id=sa;Password=hello",
         "A fairly complicated password, like a guid: 8B4B0D73-84C9-4A1E-8DD2-9A189F84FD9B");
    
    
    public static string EncryptString(string source, string key)
    {
        Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(key, salt);
        byte[] derivedKey = deriveBytes.GetBytes(derivedKeySize);
    
    
        Rijndael rijndael = Rijndael.Create();
    
        rijndael.Mode = cipherMode;
        rijndael.Padding = paddingMode;
        rijndael.KeySize = keySize;
        rijndael.BlockSize = blockSize;
        rijndael.FeedbackSize = blockSize; // no bigger than the blocksize
    
        rijndael.Key = derivedKey;
        rijndael.IV = iv;
    
        ICryptoTransform transform = rijndael.CreateEncryptor();
    
        byte[] encoded = Encoding.UTF8.GetBytes(source);
    
        byte[] target = transform.TransformFinalBlock(encoded, 0, encoded.Length);
        return Convert.ToBase64String(target);
    }
    
    public static string DecryptString(string source, string key)
    {
        Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(key, salt);
        byte[] derivedKey = deriveBytes.GetBytes(derivedKeySize);
    
        Rijndael rijndael = Rijndael.Create();
    
        rijndael.Mode = cipherMode;
        rijndael.Padding = paddingMode;
        rijndael.KeySize = keySize;
        rijndael.BlockSize = blockSize;
        rijndael.FeedbackSize = blockSize; // no bigger than the blocksize
    
        rijndael.Key = derivedKey;
        rijndael.IV = iv;
    
        ICryptoTransform transform = rijndael.CreateDecryptor();
    
        byte[] decoded = Convert.FromBase64String(source);
        byte[] target = transform.TransformFinalBlock(decoded, 0, decoded.Length);
    
        return Encoding.UTF8.GetString(target);
    }
    
        private static readonly byte[] iv = {
            0x30,0xA6,0x65,0xDE,0x8C,0x63,0x17,0x44,
            0xB6,0xFD,0xEA,0x5F,0x76,0xA1,0x1C,0x5F
        };
    
        private static readonly byte[] salt = {
            0xF9,0x39,0x0C,0xE0,0x22,0xE0,0x8E,0x84,
            0xB2,0x05,0x1E,0xA8,0x6D,0x1C,0x39,0xAC
        };
    
        private const int keySize = 256;
        private const int blockSize = 128;
        private const CipherMode cipherMode = CipherMode.CBC;
        private const PaddingMode paddingMode = PaddingMode.PKCS7;
        private const int derivedKeySize = 32;
    

    【讨论】:

      【解决方案4】:

      任何形式的加密都只与用于保护加密密钥的方法一样强大,大多数系统仍然难以真正将受保护的数据与其密钥或其他解密方法分开。例如,访问密码数据库的攻击者可以首先发起离线字典攻击以获取用户密码,然后以这些用户身份登录并“合法”请求在线服务提供商进行解密。更糟糕的是,获得加密密钥的内部人员或持续攻击者可以下载整个数据库并离线执行解密。

      为了防御此类攻击,外部加密服务可以将加密数据与解密功能完全分开。这确保了数据加密不能被逆向工程,并且任何解密都必须在加密服务的合作下授权——即使是离线的。

      看看这个可以帮助您进行每用户加密的框架:https://virgilsecurity.com/purekit-mariadb-plugin/

      该框架提供以下功能:

      密码强化加密。您不会存储用户密码或其哈希值。 PureKit 保护用户或内部密码免受数据泄露以及在线和离线攻击。

      每用户加密。 PureKit 具有强大而快速的数据加密功能,可根据每用户对任何大小的文件进行。

      基于角色的加密。 PureKit 为您提供创建和管理组(角色)的功能,并使用范围(权限)允许和拒绝他们访问用于加密资源的加密密钥比如文件和数据

      安全的数据和文件共享。 PureKit 允许您和您的用户使用 Virgil 密钥管理服务安全地共享数据。

      加密独立于数据库安全。 PureKit 提供端到端加密,因此,数据安全不依赖于任何设备、网络或云提供商

      入侵后安全性。通过要求同时访问数据库和远程加密服务器以解锁受保护的记录,PureKit 允许您保护敏感数据(例如 PII、PHI 和密码)免遭未经授权的访问,甚至如果数据库或其他在线存储设施遭到破坏。

      用户密码和密钥的零知识。 PureKit 提供数据和密码加密的方式可以防止未经授权的各方了解有关密码或加密密钥的任何信息。此外,Virgil Security 无权访问您的数据。

      被盗数据库即时失效。 PureKit 允许远程轮换密钥和记录,以防数据库被盗。

      【讨论】:

        猜你喜欢
        • 2011-03-14
        • 1970-01-01
        • 1970-01-01
        • 2018-05-06
        • 2017-01-01
        • 1970-01-01
        • 2011-09-30
        • 2012-04-03
        • 2011-06-18
        相关资源
        最近更新 更多