.NET DPAPI和AES加密:感知检查

问题描述:

我正要为我目前正在编写的网站编写一个新的加密系统,并且想要看看我是否能够在我得到之前让某人感知检查它如果可能,开始!.NET DPAPI和AES加密:感知检查

更新:应该更清楚我的原始问题。我需要加密一些用户数据,我还需要能够在以后的数据中读回。而且,我还需要存储用户密码或密码的散列,以便在登录时验证用户。

的计划是:

  1. 主密钥:创建DPAPI关键制定者应用采取了基于文本的主密钥,通过DPAPI进行加密,然后将加密的输出保存到文本文件在服务器上。这是我每次将网站移至新服务器时执行的一次性任务。主密钥将用于执行AES加密。

  2. 当新用户登记:

    2.1。保存密码数据/密码数据的散列。

    2.2。加载主密钥文件,使用DPAPI解密密钥。使用解密的主密钥和每个用户数据的新随机IV创建AES加密的字符串。通过在加密字符串前添加相应的随机IV,保存每个加密字符串,并插入数据库中的varchar列。

  3. 当用户登录:

    3.1。匹配密码哈希以验证用户。

    3.2。对于每个加密用户数据字段,将内容分为两部分:IV和加密数据。从DPAPI和IV中取得主密钥,解密数据并在屏幕上显示。

这听起来怎么样?上述有没有明显的缺陷?

我不熟悉这个,以前曾经使用过这种东西的企业库安全(这在.NET核心中不再可用!),所以任何帮助都会被大量赞赏!

+1

散列通常比加密密码要好。 –

+0

**不要加密密码**,当攻击者获取数据库时,他也会得到加密密钥。使用随机盐在HMAC上迭代大约100毫秒的持续时间,并用散列表保存盐。使用诸如password_hash,PBKDF2,Bcrypt和类似函数的函数。关键是要让攻击者花费大量时间通过强力查找密码。有关更多信息,请参阅@bartonjs的答案。 – zaph

+0

我明白使用哈希是一个好主意,但在这种情况下 - 黑客不会从数据库获取加密密钥,因为密钥本身会使用DPAPI进行加密。话虽如此,我仍然打算使用密码散列法,并且使用DPAPI + aes来处理非密码用户字段 – Delosdos

忽视的问题密码,只是考虑用户数据,你的方案很好,但可以改进。

基本上,你有一个主密钥 - 对称密钥或也许16或32个字节,即静止(在磁盘上)保护,并且你解密此在存储器服务器上。

用户数据使用主密钥进行加密,每个数据片段都随机使用IV。一定要使用密码强的随机数据。

您正在将IV和密文一起存储,这很好。尽管IV和密文是二进制的,所以您必须使用blob数据库类型,或者使用Base64将二进制代码存储为varchar。

你应该考虑增加一些什么形式的篡改检测。例如,您可以使用两个主密钥 - 一个用于加密/解密,另一个用于数据上的HMAC。你会使用加密密钥对数据进行加密,然后,在IV +密文(使用HMAC第二主密钥)申请的HMAC和存储HMAC沿着IV和密文(你甚至可以只追加的话)。解密之前,您验证HMAC。这告诉你IV +密文中的任何内容是否已经改变。

你没有提到填充。如果使用AES CBC模式,如果数据不是16字节的倍数,则需要填充数据。随着填充,你就必须要小心,你不小心提供“填充神谕”,其中一个攻击者可以发送任意的密文到服务器,从服务器的响应告诉攻击者要么“填充错误”或“无效解密“ - 即服务器响应有所不同。

如果使用AES GCM模式,然后HMAC相当于是内置的 - 你只需要单一的主键,GCM本身将检测到的密文的篡改。这也可以让你包含“关联数据”,这不是加密的一部分,但包含在“认证”中,就好像它包含在HMAC中一样。例如,用户名“Joe”可以作为关联数据包含在Joe数据的GCM加密中。然后,当GCM模式解密数据时,它不仅会检测到IV +密文的篡改,而且用户名还必须是“Joe” - 请注意,“Joe”在此处未加密。

个人IV,随机每次,对每片数据,是一个很好的方法。您可能还会考虑在更换之前使用主密钥的时间。它应该有一个有限的生命周期,当它被“旋转”或“滚动”或“重新生成密钥”(都意味着同样的事情 - 你正在取代它),你需要一些方法来重新加密一切。您想要定期更改主密钥(可能是3个月,可能是一年),以1)限制万一主密钥受到攻击而暴露的数据量(例如,只有3个月的价值)和2)限制单个密钥用于加密的数据量(因为从技术上讲,可以使用单个密钥加密多少数据并且仍然是数学上的“安全”)有限。

+0

@zaph OP描述了使用DPAPI保护密钥。那么这将取决于Windows - 它可能与Windows userid(即安全主体)或机器相关联。这超出了这个问题的范围,DPAPI究竟如何保护密钥。详情请参阅Google“Windows数据保护API”。 –

+0

了解,评论删除。 – zaph

+0

@JimFlood谢谢您的全面回答。我打算使用RijndaelManaged()。GenerateIV()创建随机IV。由于.NET中没有AES HCM模式(在撰写本文时),我可能会使用AES CBC并使用您的HMAC和两键建议。我找到了一个例子,其中有人正在做一些非常相似的事情:[链接到Github](https://gist.github.com/jbtule/4336842#file-aesthenhmac-cs)。我可能会使用它作为基础,交换到RijndaelManaged并进行一些修改以添加配置版本控制,以便稍后更改salt大小/迭代很容易 – Delosdos

如果可以避免,则不应该存储密码。

我不清楚密码是在步骤1中。如果一个新用户没有显示出来,直到第2步,其密码是这样的吗?

无论如何,对于您的用户来说,更好的计划是使用/保存衍生材​​料。例如,在新用户注册这样做

byte[] exportBytes; 
byte[] exportSalt; 
int exportPasswordSettingsVersion = YourSystemConfiguration.NewPasswordSettingsVersion; 

using (Rfc2898DeriveBytes registerer = new Rfc2898DeriveBytes(
    newUserPassword, 
    YourSystemConfiguration.GetSaltSize(exportPasswordSettingsVersion), 
    YourSystemConfiguration.GetIterationCount(exportPasswordSettingsVersion))) 
{ 
    exportSalt = registerer.Salt; 

    exportBytes = registerer.GetBytes(
     YourSystemConfiguration.GetDerivedKeySize(exportPasswordSettingsVersion)); 
} 

然后导出盐字节(其中随机为你生成),得到的密码字节,SETT作为用户的配置文件的一部分。当用户来到登录,您加载这些值返回并检查它们匹配:

using (Rfc2898DeriveBytes verifier = new Rfc2898DeriveBytes(
    inputPassword, 
    loadedProfile.Salt, 
    YourSystemConfiguration.GetIterationCount(loadedProfile.PasswordSettingsVersion))) 
{ 
    byte[] verifyBytes = registerer.GetBytes(loadedProfile.PasswordVerify.Length); 

    if (!ConstantTimeEquals(verifyBytes, loadedProfile.PasswordVerify)) 
    { 
     return false; 
    } 

    if (loadedProfile.PasswordSettingsVersion < YourSystemConfiguration.GetIterationCount(exportPasswordSettingsVersion)) 
    { 
     // Re-derive their password and save it with your newer (stronger, presumably) cryptographic settings. 
    } 

    return true; 
} 

此方案:

  • 采用RFC2898的PBKDF2算法来推导从密码的钥匙,储存由此而来值比存储密码要好,因为如果您的凭证数据库受到损害,它不会泄露密码。
  • 为每个新用户使用新的随机盐。
  • 保存(和负载)有关,当设置密码,所以你可以改变你的默认设置在未来的什么被用于设置的信息(也可以在密码更改或升级登录重新生成)。
  • 不使用DPAPI(DPAPI不​​坏,但它只有Windows版本,如果你正在使用.NET的核心,那么你可能需要一个跨平台解决方案)
+0

道歉,我的原始问题并不十分清楚。我已经更新了它。感谢代码示例,非常有用。 – Delosdos

+0

另外,就散列而言,您是否认为将blob中的salt/hash /迭代次数保存在单个数据库列中会有危害? – Delosdos

+0

同样,您是否看到存储IV以及非密码用户数据字段的加密AES字符串有什么危害? – Delosdos