正确地在.NET中腌制哈希

时间:2014-04-06 23:11:28

标签: asp.net sql-server vb.net security encryption

我正在为我公司的当前产品实施一个新的密码存储过程。它是一个带有MS SQL Server的ASP.NET应用程序。

在他们使用相同的公共种子加密3DES加密并检查用户身份验证之前,他们只是使用相同的种子解密密码。

我正在使用无法解密的salt实现SHA256哈希。

首先,我知道每个用户的每种盐应该是不同的,但我不明白这种盐的储存地点在哪里?如果它存储在数据库中,这是否会使其无效?

我的想法是通过取用户名的前4个字母,第一个名字的前3个字母和姓氏的前3个字母来创建一个盐,并将其转换为md5哈希,然后将其用作没有存储在数据库中的盐。

此序列将是服务器端,因此没有黑客可以在没有源代码的情况下知道序列。

我在这里做的有什么问题吗?

SHA256也可以接受,或者我应该关注SHA512。

由于

3 个答案:

答案 0 :(得分:2)

如果你必须自己实现这一点(我个人是MembershipReboot的粉丝,那么你应该看看PBKDF2密码存储。

它不仅可以正确实现盐,还支持多次迭代,以帮助阻止暴力攻击。您可以找到迭代次数here的指导。

另外值得注意的是,如果验证是一个问题,PBKDF2是可接受的NIST standard

要回答关于将盐保存在数据库中的问题,不需要保密。盐的目的只是为了防止哈希的预先计算,而不是混淆或加密。以任何方式。

Rainbow tables通过预先计算密码来工作,然后在强制执行时查找彩虹表中的相应散列。通过Google搜索MD5哈希,您实际上可以看到它有多简单,并且通常在搜索结果中您可以找到原始输入。

例如,如果你谷歌字符串' 5f4dcc3b5aa765d61d8327deb882cf99',你会发现它对应于'密码'。

通过使用salt,攻击者必须为每个可能的密码计算唯一的哈希值,而不仅仅是通用列表。

答案 1 :(得分:2)

  

“我在这里做的事情有什么问题吗?”

是的,有。不安全不是安全。仅仅因为盐很难找到并不意味着它非常安全。与强制哈希相比,弄清楚如何创建盐将是一块蛋糕。

没有必要保密盐,只需为每个用户创建一个随机数,并与密码一起存储。盐的目的是消除使用彩虹表来破解表中所有密码的优点。对于大多数用户来说,盐必须是不同的(最好是唯一的,但这并不重要)。

答案 2 :(得分:0)

盐不应该是私人的。它与哈希一起分发,通常在它之前。盐的唯一目的是确保如果相同的数据被加密两次,您将永远得不到相同的输出。根据定义,它必须是唯一的,但不需要随机性或保密性。

您也不应该为每个用户创建一个随机数。 每个加密的盐需要不同,即使对于同一个用户也是如此。只需生成随机盐,使用它来创建哈希,将盐添加到哈希,将所有内容编码为base64,然后存储它。要验证您解码为二进制的哈希,请提取salt,使用它来哈希输入数据并与解码后的哈希进行比较。

像盐一样有效的东西是GUID。根据定义,128位是唯一的,虽然不是完全随机的,并且可以立即使用而无需任何额外的代码以下是AES-256加密和解密的示例。请记住,在实际的实现中,您希望将纯文本和密钥存储在SecureString对象中......

Private blockSize = 128
Private keySize = 256
Private cipherMode = CipherMode.CBC

Protected Function AESEncryptStringToBase64(strPlainText As String, strKey As String) As String
    Dim Algo As AesManaged = AesManaged.Create()
    With Algo
        .BlockSize = blockSize
        .FeedbackSize = blockSize
        .KeySize = keySize
        .Mode = cipherMode
        .IV = Guid.NewGuid().ToByteArray()
        .Key = Encoding.ASCII.GetBytes(strKey)
    End With

    Using Encryptor As ICryptoTransform = Algo.CreateEncryptor()
        Using MemStream As New MemoryStream
            Using CryptStream As New CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write)
                Using Writer As New StreamWriter(CryptStream)
                    Writer.Write(strPlainText)
                End Using

                AESEncryptStringToBase64 = Convert.ToBase64String(Algo.IV.Concat(MemStream.ToArray()).ToArray())
            End Using
        End Using
    End Using
End Function

Protected Function AESDecryptBase64ToString(strCipherText As String, strKey As String) As String
    Dim arrSaltAndCipherText As Byte() = Convert.FromBase64String(strCipherText)

    Dim Algo As AesManaged = AesManaged.Create()
    With Algo
        .BlockSize = blockSize
        .FeedbackSize = blockSize
        .KeySize = keySize
        .Mode = cipherMode
        .IV = arrSaltAndCipherText.Take(16).ToArray()
        .Key = Encoding.ASCII.GetBytes(strKey)
    End With

    Using Decryptor As ICryptoTransform = Algo.CreateDecryptor()
        Using MemStream As New MemoryStream(arrSaltAndCipherText.Skip(16).ToArray())
            Using CryptStream As New CryptoStream(MemStream, Decryptor, CryptoStreamMode.Read)
                Using Reader As New StreamReader(CryptStream)
                    AESDecryptBase64ToString = Reader.ReadToEnd()
                End Using
            End Using
        End Using
    End Using
End Function