1

我们有一个表格,我们保存用户/密码和其他一些数据。每条记录的密码字段都必须加密。我们决定使用 AesCryptoServiceProvider 进行加密,并手动创建了一次 rgbKey。然后加密所有用户密码并将记录插入到我们的表中,其中密码字段使用我们的 rgbKey 加密。

我们在负载均衡器后面有几台服务器,每台服务器都应该读取这些记录并可以解密密码字段值。一开始我们将base64StringFormat中的rgbKey放入我们的dll(API)中,同样所有的服务器都将使用这个API并且可以解密加密的值。

但是,将 rgbKey 保存在 dll 文件中是非常不安全的。我们讨论了是否将密钥保留在 DPAPI 中。在解密时,在我们的任何服务器上,我们将从 DPAPI 获取我们的密钥并成功解密加密值。

我认为我可以在具有当前用户模式的任何服务器中生成一次受保护的密钥,然后将其保存在我们的通用 dll 中。每个使用公共 dll 的服务器,将这个受保护的密钥(字节 [])提供给具有相同用户的 DPAPI,可以获得不受保护的密钥值。但是它只在受保护的机器上工作,在其他机器上它给出错误:“密钥在指定状态下无效。”

我的问题是如何保护我的永久 rgbKey 以便我可以从所有机器访问它?看看下面类似的测试控制台应用程序,我的方法有什么问题?

我为我的测试控制台应用程序提供了一个示例代码:

首先,我在本地机器上运行我的 PDPAPI() 函数:

    static void PDPAPI() {
        System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
        byte[] rgbKey = encoding.GetBytes( "MyRgbKey" );
        byte[] protectedData = ProtectedData.Protect( rgbKey, null, DataProtectionScope.CurrentUser );
        string base64ProtectedData = Convert.ToBase64String( protectedData );
        Console.WriteLine( "base64ProtectedData:{0}", base64ProtectedData );            
    }

然后硬编码添加到我的 UDPAPI() 函数 base64ProtectedData 从上述执行中获得的值,重建解决方案:

    static void UDPAPI() {
        string base64ProtectedData = "****";
        byte[] protectedData = Convert.FromBase64String( base64ProtectedData );
        byte[] unProtectedData = ProtectedData.Unprotect( protectedData, null, DataProtectionScope.CurrentUser );
        string base64unProtectedData = Convert.ToBase64String( unProtectedData );
        Console.WriteLine( "base64unProtectedData:{0}", base64unProtectedData );
    }            

现在,如果我在本地机器上运行 UDPAPI() 函数,它会成功取消保护数据,但是如果我将控制台应用程序迁移到任何其他服务器,并使用我的网络用户登录该服务器,控制台应用程序会给出错误“密钥无效在指定状态下使用。”。

4

1 回答 1

0

老实说,对于密码加密,如果您使用单向哈希而不是使用密码的明文,只需哈希用户输入并进行比较,您将不会遇到密钥存储问题。在 C# 中使用的典型内容是 PBKDF2 ( Rfc2898DeriveBytes )。有关其他选项,请参阅Crypto:什么使散列函数适合密码散列?

密钥存储问题总是很困难,DPAPI 是一个相当不错的选择,它可以保护同一台机器上其他用户的密钥,并且比将其存储在 DLL 中要好得多,但要了解它在做什么,它是用您正在运行的任何 Windows 用户的密码哈希(实际上它从密码哈希中做更多的事情,密钥派生、轮换等),这就是为什么您不能直接在服务器上使用从本地计算机加密的数据的原因。要使用 DPAPI,您必须在每台服务器上单独加密您的密钥(这不是一件坏事)。

最好不要对您的密钥进行硬编码,不是因为它可以访问,而是因为在您需要时或在不同的设置中更容易更改。通常,如果没有专门的硬件,您最多只能将密钥与数据分开。您可以通过加密密钥使事情变得更加困难,但您只是添加了另一个攻击者也必须访问的密钥,没有理想的解决方案。

如果您想要一种能够随时间更改密钥的简单方法,我已将keyczar 框架移植到 c#,它具有旋转密钥所需的机制,以便您在加密新数据时仍然可以解密旧数据,但它没有确实在密钥存储可访问性方面提供了更多安全性。

于 2013-03-14T13:19:02.853 回答