用基本的安全措施存储密码的过程相当简单:
用盐散列密码
为每个用户/密码使用不同的盐
将哈希密码的salt存储在数据库中
当他们尝试login时,通过相同的方法运行尝试的PW; 比较结果。
如果他们input正确的密码,散列的PW将匹配。 散列保护用户免受攻击以及pipe理员走在显示members表的屏幕上。
创build盐和散列PW
' salt size is 32 (0-31 Private Const SaltSize As Integer = 31 ... Dim dbPW As String = TextBox1.Text Dim dbSalt = CreateNewSalt(SaltSize) ' eg: "dsEGWpJpwfAOvdRZyUo9rA==" Dim SaltedPWHash As String = GetSaltedHash(dbPW, dbSalt) ' examples: ' using SHA256: bbKN8wYYgoZmNaG3IsQ2DPS2ZPIOnenl6i5NwUmrGmo= ' using SHA512: ' 0vqZWBIbOlyzL25l9iWk51CxxJTiEM6QUZEH1ph+/aNp+lk4Yf8NYv8RLhYtbqCNpOqO3y8BmM+0YWtbAhE+RA=="
存储PW散列和salt作为用户logging的一部分。 盐不是秘密的,但如果用户更改密码,则更改密码。
比较login尝试
' check if PW entered equals DB Dim pwTry = TextBox2.Text ' hash the login attempt using the salt stored in the DB Dim pwLogin = GetSaltedHash(pwTry, dbSalt) ' compare the hash of what they entered to whats in the DB: If String.Compare(SaltedPWHash, pwLogin, False) = 0 Then ' okay! Console.Beep() End If
如果用户input相同的密码,它应该导致相同的散列,就像那样简单。 哈希代码并不是那么复杂:
散列方法
Private Function GetSaltedHash(pw As String, salt As String) As String Dim tmp As String = pw & salt ' or SHA512Managed Using hash As HashAlgorithm = New SHA256Managed() ' convert pw+salt to bytes: Dim saltyPW = Encoding.UTF8.GetBytes(tmp) ' hash the pw+salt bytes: Dim hBytes = hash.ComputeHash(saltyPW) ' return a B64 string so it can be saved as text Return Convert.ToBase64String(hBytes) End Using End Function Private Function CreateNewSalt(size As Integer) As String ' use the crypto random number generator to create ' a new random salt Using rng As New RNGCryptoServiceProvider ' dont allow very small salt Dim data(If(size < 7, 7, size)) As Byte ' fill the array rng.GetBytes(data) ' convert to B64 for saving as text Return Convert.ToBase64String(data) End Using End Function
使用GUID( System.Guid.NewGuid.ToString )作为盐是很诱人的,但使用密码随机数生成器并不难。
与散列密码一样,返回string由于编码而更长。
每次用户更改密码时都会创build一个新的salt。 不要使用全球性的食盐,它会破坏目的。
您也可以多次散列PW。 部分关键在于如果受到攻击时要花费很长时间来尝试各种组合。
这些函数是Shared / static类成员的理想候选者。
还请注意, Kenneth所撰写的文章非常值得一读。
请注意, 文章提到The salt should be stored in the user account table alongside the hash这并不意味着你必须在数据库中有一个Salt列。 您可以在链接的文章中看到以下内容:
Dim dbPW As String = TextBox1.Text Dim dbSalt = CreateNewSalt(SaltSize) ' get the salted PW hash Dim SaltedPWHash As String = GetSaltedHash(dbPW, dbSalt) ' store salt with the hash: SaltedPWHash = String.Format("{0}:{1}", dbSalt, dbPW) ' salt + ":" + hashed PW now ready to store in the db
从哈希密码中分离盐:
Dim SaltAndPWHash = rdr.Item("PWHash").ToString() Dim split = SaltAndPWHash.Split(":"c) ' split on ":" Dim Salt = split(0) ' element(0) == salt Dim StoredPWHash = split(1) ' element(1) == hashed PW
你需要这两个部分:在散列试图loginPW后,将其与split(1)进行比较。