.NET DPAPI和AES加密:感知检查
我正要为我目前正在编写的网站编写一个新的加密系统,并且想要看看我是否能够在我得到之前让某人感知检查它如果可能,开始!.NET DPAPI和AES加密:感知检查
更新:应该更清楚我的原始问题。我需要加密一些用户数据,我还需要能够在以后的数据中读回。而且,我还需要存储用户密码或密码的散列,以便在登录时验证用户。
的计划是:
主密钥:创建DPAPI关键制定者应用采取了基于文本的主密钥,通过DPAPI进行加密,然后将加密的输出保存到文本文件在服务器上。这是我每次将网站移至新服务器时执行的一次性任务。主密钥将用于执行AES加密。
-
当新用户登记:
2.1。保存密码数据/密码数据的散列。
2.2。加载主密钥文件,使用DPAPI解密密钥。使用解密的主密钥和每个用户数据的新随机IV创建AES加密的字符串。通过在加密字符串前添加相应的随机IV,保存每个加密字符串,并插入数据库中的varchar列。
-
当用户登录:
3.1。匹配密码哈希以验证用户。
3.2。对于每个加密用户数据字段,将内容分为两部分:IV和加密数据。从DPAPI和IV中取得主密钥,解密数据并在屏幕上显示。
这听起来怎么样?上述有没有明显的缺陷?
我不熟悉这个,以前曾经使用过这种东西的企业库安全(这在.NET核心中不再可用!),所以任何帮助都会被大量赞赏!
忽视的问题密码,只是考虑用户数据,你的方案很好,但可以改进。
基本上,你有一个主密钥 - 对称密钥或也许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)限制单个密钥用于加密的数据量(因为从技术上讲,可以使用单个密钥加密多少数据并且仍然是数学上的“安全”)有限。
@zaph OP描述了使用DPAPI保护密钥。那么这将取决于Windows - 它可能与Windows userid(即安全主体)或机器相关联。这超出了这个问题的范围,DPAPI究竟如何保护密钥。详情请参阅Google“Windows数据保护API”。 –
了解,评论删除。 – zaph
@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的核心,那么你可能需要一个跨平台解决方案)
散列通常比加密密码要好。 –
**不要加密密码**,当攻击者获取数据库时,他也会得到加密密钥。使用随机盐在HMAC上迭代大约100毫秒的持续时间,并用散列表保存盐。使用诸如password_hash,PBKDF2,Bcrypt和类似函数的函数。关键是要让攻击者花费大量时间通过强力查找密码。有关更多信息,请参阅@bartonjs的答案。 – zaph
我明白使用哈希是一个好主意,但在这种情况下 - 黑客不会从数据库获取加密密钥,因为密钥本身会使用DPAPI进行加密。话虽如此,我仍然打算使用密码散列法,并且使用DPAPI + aes来处理非密码用户字段 – Delosdos