Il processo per memorizzare le password con una misura di sicurezza di base è abbastanza semplice:
- Hash le password con sale
- Utilizza un salt diverso per ogni utente/password
- Memorizza il sale con la password hash nel DB
- Quando tentano di accedere, esegui la PW tentata con lo stesso metodo; confronta il risultato.
Se hanno inserito la password corretta, le PW con hash corrisponderanno. L'hashing protegge gli utenti dagli attacchi così come il custode che cammina davanti a uno schermo con i members
tavola in esposizione.
Creazione di sale e hash del 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=="
Archivia l'hash PW e il sale come parte del record dell'utente. Il sale non è segreto, ma cambialo quando/se l'utente cambia la propria password.
Confronto di un tentativo di accesso
' 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
Se l'utente inserisce la stessa PW, dovrebbe risultare lo stesso hash, è così semplice. Il codice di hashing non è poi così complicato:
Metodi hash
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
- Si è tentati di usare qualcosa come un GUID (
System.Guid.NewGuid.ToString
) come il sale, ma non è poi così difficile usare il generatore di numeri casuali crittografici. - Come per la password con hash, la stringa di ritorno è più lunga a causa della codifica.
- Crea un nuovo salt ogni volta che l'utente cambia la propria password. Non usare un sale globale, vanifica lo scopo.
- Puoi anche eseguire l'hashing della PW più volte. Parte della chiave è far sì che ci voglia molto tempo per provare tutte le varie combinazioni se/quando vengono attaccati.
- Le funzioni sono i candidati ideali per
Shared
/static
membri della classe.
Nota anche l'articolo collegato da Kenneth vale la pena leggerlo.
Tieni presente che l'articolo
menziona The salt should be stored in the user account table alongside the hash
Questo non significa che devi avere un Salt
colonna nel DB. Puoi vedere quanto segue nell'articolo collegato:
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
Per dividere il sale dalla password con hash:
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
Hai bisogno di entrambe le parti:dopo aver eseguito l'hashing del tentativo di accesso in PW, confrontalo con split(1)
.