Reputation: 449
I am writing an ASP.NET program where I need to store the users password in the database. But I get a password mismatched when I Compare the password from the database with the user input password. Even if the users password is correct.
Password Hashing:
string PasswordSalt = Crypto.HashPassword(DateTime.Now.ToString());
string hashPassword = Crypto.HashPassword(formcollection["PassWord"]); //Hash User PassWord
user.PassWord = Crypto.HashPassword(PasswordSalt + hashPassword);//Add Salt to Password For Futher Security
user.PassWordSalt = PasswordSalt;
Password Verification:
Users ThisUser = Users.UsersGetByEmail((string)Session["email"]);
string checkpassword = ThisUser.PassWord;
//User Inputed password.
string password = user.PassWord;
if (password != null)
{
//Need to fix.
string encrypt_password = Crypto.HashPassword(password);
string salted_password = Crypto.HashPassword(ThisUser.PassWordSalt + encrypt_password);
//bool does_password_match = Crypto.VerifyHashedPassword(checkpassword, password);
if (checkpassword == salted_password)
{
//Check if the inputed password matches the password from the Database.
//Remember to give session based on the user_id.
Session["user_id"] = ThisUser.Id;
return RedirectToAction("Promise");
}
else
{
ModelState.AddModelError("PassWord", "Wrong Password, Please Enter Correct Password");
return View(user);
}
Upvotes: 1
Views: 3411
Reputation: 7663
I've never used it, but based on the documentation...
Crypto.HashPassword adds the salt for you and returns a base-64 encoded string with all the details in it to verify the password. So, you do NOT need to add a salt yourself.
All you need to do is store the hash result (base64EncodedHash
below) in the DB, and then use it with VerifyHashedPassword to authenticate later. E.g. make a unit test like so:
var base64EncodedHash = Crypto.HashPassword("password");
Assert.IsTrue( Crypto.VerifyHashedPassword( base64EncodedHash, "password" ) );
Assert.IsFalse( Crypto.VerifyHashedPassword( base64EncodedHash, "otherPass") );
To translate this to your code:
user.PassWord = Crypto.HashPassword(formcollection["PassWord"]);
Then to verify (comments added for quirks I see):
//Why are you storing "email" in Session before user is validated??? Seems off.
Users ThisUser = Users.UsersGetByEmail((string)Session["email"]);
string userInputPassword = user.PassWord; //this should be coming from POST
if( ThisUser != null && Crypto.VerifyHashedPassword(ThisUser.PassWord, userInputPassword) ) {
Session["user_id"] = ThisUser.Id;
return RedirectToAction("Promise");
}
else {
ModelState.AddModelError("PassWord","Your username or password are incorrect");
return View(user);
}
Ideally, as I somewhat indicated by my change of your error text...you also want to give the user the same error message whether the username/email or password are wrong. Your code, as is, probably returns a different error if the email doesn't return an account, but you don't want to give that much info to brute-force attackers.
You also need to put in some brute-force checking so that if they attempt too many times with failures, block that IP address for X amount of time., etc.
And, as someone said...when it comes to security...until you're the expert...it's best to use pre-existing code/frameworks to mitigate you risks.
Upvotes: 2