我正准备为我目前正在工作的一个网站编写一个新的加密系统,并想看看我是否能让人感觉到-如果可能的话,在我开始之前检查它!
更新:应该更清楚我最初的问题。我需要加密一些用户数据,我也需要能够在以后的数据中读取这些数据。此外,我还需要存储用户密码或密码哈希,以便在登录时验证用户。。
计划是:
这听起来怎么样?上述问题是否存在明显的缺陷?
我对此很陌生,以前我用过企业图书馆安全来处理这类东西(这在.NET内核中不再可用了!),所以我们会非常感谢您的帮助!
发布于 2016-07-17 18:32:49
忽略密码问题,只考虑用户数据,您的方案是好的,但可以改进。
基本上,您有一个主密钥--一个对称密钥或16或32个字节,它在rest (磁盘上)受到保护,并在服务器上的内存中解密。
使用主密钥对用户数据进行加密,对每一段数据使用随机IV。确保使用加密强随机数据。
你把IV和密文放在一起,这很好。尽管IV和密文是二进制的,所以您必须使用blob数据库类型,或者使用Base64对二进制文件进行编码,以便将其存储为varchar。
您应该考虑添加某种形式的篡改检测。例如,您可以使用两个主密钥-一个用于加密/解密,另一个用于数据上的HMAC。您将使用加密密钥对数据进行加密,然后在IV +密文(使用HMAC的第二个主密钥)上应用HMAC,并将HMAC存储在IV和密文旁边(您甚至可以附加它)。在解密之前,您要验证HMAC。这将告诉您,如果IV +密文中的任何内容已被更改。
你没提到填充物。如果使用AES CBC模式,则如果数据不是16个字节的倍数,则需要对其进行填充。使用填充时,您必须小心,不要意外地提供“填充oracle",攻击者可以向服务器发送任意密文,服务器的响应告诉攻击者”填充错误“或”无效解密“--即服务器响应中存在差异。
如果您使用AES GCM模式,那么等效的HMAC是内置的-您只需要一个主密钥,而GCM本身将检测到密文的篡改。这还允许您包含“关联数据”,这不是加密的一部分,而是包含在“身份验证”中,也就是说,就好像它包含在HMAC中一样。例如,用户名"Joe“可以作为关联数据包含在Joe的数据的GCM加密中。然后,当GCM模式对数据进行解密时,它不仅会检测到对IV +密文的篡改,而且用户名也必须仍然是"Joe“--注意这里没有加密"Joe”。
个人IV,每一次随机,对于每一段数据,是一个非常好的主意。您还可以考虑在替换主键之前使用了多长时间。它的寿命应该是有限的,当它被“旋转”、“滚动”或“重键”(所有的意思都是相同的东西--你正在替换它)时,你需要一些方法来重新加密所有的东西。您希望定期更改主密钥(可能是3个月,可能是一年)到1)限制在主密钥被泄露时公开的数据量(例如,只有3个月的值)和2)限制用于加密的单个密钥的数据量(因为在技术上,您可以用单个密钥加密多少数据,但在数学上仍然是“安全的”)。
发布于 2016-07-17 00:41:54
如果你能避免密码的话,你就不应该储存密码。
我不清楚第一步中的密码是什么。如果一个新用户直到第二步才出现,这是谁的密码?
无论如何,对于您的用户来说,一个更好的计划是使用/保存派生材料。例如,在新用户注册时,请执行以下操作
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;
}这一计划:
https://stackoverflow.com/questions/38416512
复制相似问题