我们有保存用户/密码和其他一些数据的表。每个记录的密码字段必须加密。我们决定使用AesCryptoServiceProvider进行加密,并手动创建rgbKey一次。然后将所有用户密码和插入的记录加密到我们的表中,其中密码字段用我们的rgbKey加密。
我们在负载均衡器后面有几台服务器,每台服务器都应该读取这些记录,并且可以解密密码字段值。在开始时,我们将base64StringFormat中的rgbKey放入我们的dll(API)中,同样所有服务器都将使用此API并可以解密加密值。
但是,将rgbKey保留在dll文件中是非常不安全的。我们讨论了是否继续关注DPAPI。在解密时,在任何我们的服务器上,我们将从DPAPI获取密钥并成功解密加密值。
我认为我可以在任何具有当前用户模式的服务器中生成一次受保护的密钥,然后将其保存在我们的常用dll中。每个服务器使用公共dll,将此受保护密钥(byte [])与同一用户的DPAPI一起提供,可以获得不受保护的密钥值。但是它只能在受保护的机器上工作,在其他机器上它会产生错误:“密钥无法在指定状态下使用。”
我为测试控制台应用程序提供了示例代码:
首先,我在本地机器上运行我的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()函数,它会成功取消保护数据,但是如果我将控制台应用程序迁移到任何其他服务器,并使用我的网络用户登录该服务器,则控制台应用程序会出错“Key无效在指定状态下使用。“。
答案 0 :(得分:0)
老实说,对于密码加密,如果您使用单向散列,而不是使用密码的明文,只需散列用户输入并进行比较,就不会出现密钥存储问题。在C#中使用的典型事项是PBKDF2(Rfc2898DeriveBytes)。有关其他选项,请参阅Crypto:What makes a hash function good for password hashing?
密钥存储问题总是很困难,DPAPI是一个相当不错的选择它可以保护密钥免受同一台机器上的其他用户的影响,并且比将它存储在DLL中要好得多,但要了解它正在做什么,它是使用您正在运行的任何Windows用户的密码哈希进行加密(实际上它正在从密码哈希中执行更多,密钥派生,轮换等),这就是为什么您不能直接在服务器上使用从本地计算机加密的数据的原因。要使用DPAPI,您必须在每台服务器上单独加密密钥(这不是一件坏事)。
最好不要对密钥进行硬编码,而不是因为它可以访问,而是因为它更容易在需要时或在不同的设置中进行更改。通常,如果没有专门的硬件,您可以做的最多就是将密钥与数据分开。您可以通过加密密钥来使事情变得更加困难,但是您只是添加了攻击者也必须访问的另一个密钥,但是没有理想的解决方案。
如果您想要一种简单的方法来随时间更改密钥,我已移植keyczar framework to c#它具有旋转密钥所需的机制,这样您仍然可以在加密新数据时解密旧数据,但是它在密钥存储可访问性方面并没有真正提供更多安全性。