c# - salted - password salt generator
¿Es esta la forma de sal y almacenar una contraseña en Db? (5)
Hay varias formas (incluso aquí en SO) y todas mencionan que la mejor manera de mantener la contraseña en la base de datos es guardar, no la contraseña, no la contraseña hased, sino almacenar el hash de una contraseña salada .
Mi pregunta es simple, poner algún código en ella, ¿es esta la manera correcta?
string username = "myUsr";
string password = "myPwd";
DateTime createDate = DateTime.UtcNow;
// Salt it
string saltedPwd = String.Concat(password, createDate.Ticks.ToString());
// Hash it
HMACSHA1 hash = new HMACSHA1(Encoding.Unicode.GetBytes(Helper.EncryptKey));
string encodedPwd = Convert.ToBase64String(
hash.ComputeHash(Encoding.Unicode.GetBytes(saltedPwd)));
// Create User in the database
db.CreateUser(username, encodedPwd, createDate);
Tabla de usuario de base
user_id | username | password | create_date | last_access | active
y al encodedPwd
sesión, use el proceso de nuevo y compruebe si el encodedPwd
es igual que la contraseña saed, hased que se proporcionó.
Mi única preocupación es, ¿ es esta la mejor manera de sacar una contraseña? ¿Está bien usar la Fecha de creación (ya que eso siempre cambiará, y leo que es mejor usar siempre una salt
diferente cada vez que codificamos una contraseña ...
O debería ser la salt
una variable completamente diferente?
¿Qué tal si prueba el método ProtectedData.Protect
?
Este método se puede usar para cifrar datos como contraseñas , claves o cadenas de conexión. El parámetro optionalEntropy le permite agregar datos para aumentar la complejidad del cifrado ; especifique null para ninguna complejidad adicional. Si se proporciona, esta información también se debe utilizar al descifrar los datos utilizando el método Desproteger.
Creo que la idea con CreateDate es suficientemente poderosa, pero cuando alguien roba su DB y su código, se revela su sal. La seguridad basada en "nadie puede borrar mi código" es una mala seguridad.
Simplemente puede duplicar la contraseña ... y usar sal del primer hash.
string Flavor(string passwd)
{
string fhash = Str2SHA1(passwd);
string salt = fhash[2] + fhash [10] + fhash[1]; // or whatever...
string realhash = Str2SHA1(hash + salt);
}
string Str2Sha1(string str){ ... }
Me pregunto por qué nadie ha mencionado a BCrypt todavía. Hay una implementación lista para usar para C #. Ver http://derekslager.com/blog/posts/2007/10/bcrypt-dotnet-strong-password-hashing-for-dotnet-and-mono.ashx
No reinvente la rueda si hay soluciones a prueba para su problema.
Probablemente su implementación sea lo suficientemente buena, pero sería mejor usar una sal con más entropía: el valor de las marcas que usa actualmente siempre estará en un rango relativamente pequeño.
Sugeriría usar algo como PBKDF2 para hacer el trabajo por ti, a través de Rfc2898DeriveBytes
:
string username = "myUsr";
string password = "myPwd";
using (var deriveBytes = new Rfc2898DeriveBytes(password, 20)) // 20-byte salt
{
byte[] salt = deriveBytes.Salt;
byte[] key = deriveBytes.GetBytes(20); // 20-byte key
string encodedSalt = Convert.ToBase64String(salt);
string encodedKey = Convert.ToBase64String(key);
// store encodedSalt and encodedKey in database
// you could optionally skip the encoding and store the byte arrays directly
db.CreateUser(username, encodedSalt, encodedKey);
}
Y para autenticar ...
string username = "myUsr";
string password = "myPwd";
string encodedSalt, encodedKey;
// load encodedSalt and encodedKey from database for the given username
byte[] salt = Convert.FromBase64String(encodedSalt);
byte[] key = Convert.FromBase64String(encodedKey);
using (var deriveBytes = new Rfc2898DeriveBytes(password, salt))
{
byte[] testKey = deriveBytes.GetBytes(20); // 20-byte key
if (!testKey.SequenceEqual(key))
throw new InvalidOperationException("Password is invalid!");
}
Su método está totalmente bien, pero digamos que alguien obtuvo su base de datos, pero no su código base. En esencia, podrían darse cuenta de que simplemente concatena la contraseña y crea la fecha, y que pueden realizar ingeniería inversa de todas las contraseñas.
Es posible que desee inyectar una cadena única que solo existe en su base de código para una protección adicional.
string username = "myUsr";
string password = "myPwd";
DateTime createDate = DateTime.UtcNow;
// Salt it
string saltedPwd = String.Concat(password, SomeOtherClass.StaticKey, createDate.Ticks.ToString());
public class SomeOtherClass
{
public static string StaticKey = "#$%#$%superuniqueblahal$#%@#$43580"; // should probably be const/readonly, but whatever
}