so I have some models being displayed in a default view. I am trying to figure out if I want to hash the password with Crypto.HashPassword() method. Do I do this in the controller or the model or where? I did research on how to do it, but I am just finding different method and not where the action takes place. Beginner to MVC and asp.net, so any point in the right direction would be major help. Thank you in advance.
3 Answers
You generally will want to perform the hash operation in the controller, and store the hash result value in the model.
Taking for example a simple user login to your website:
- When the user account is first created, you'll call Crypto.HashPassword(pwd) to calculate the hash value of the password the user has set. You can do this in the controller, inside the action where the user registers a new account.
- The resulting hash value needs to be stored in the Model (e.g. in the DB) so that you can retrieve it later.
- When the same user tries to login next time, you'll need to call Crypto.VerifyHashedPassword(storedHash, submittedPwd). Crypto class hashes the submitted pwd with the same IV and Salt, and returns True if they match (pwd is correct), or False if they don't (pwd is wrong).
If you are new to MVC and ASP.Net, you may want to look at ASP.Net Forms Authentication (such as this page on MSDN), which you can use for authenticating users without having to roll your own custom solution.
2 Comments
Crypto.HashPassword(pwd) on the submitted password. Then compare the resulting hash value to the value stored in the Model" That doesn't work because HashPassword is not deterministic. You need to use Crypto.VerifyHashedPassword.I'd define the user class like this:
public class User
{
private string PasswordHash {get; set;} //assuming your db supports serializing private properties. If not increase visibility as necessary.
public void SetPassword(string newPassword)
{
PasswordHash = PasswordHasher.CreateHash(newPassword);
}
public bool VerifyPassword(string passwordCandidate)
{
return PasswordHasher.Verify(PasswordHash, passwordCandidate);
}
}
I would not have a User.Password property, since you never store it, and there is no simple mapping between passwords and hashes.
The PasswordHash property should only be accessed by the database serializer and through these two functions. The controller should fetch the user and then call these methods to verify/change the password.
I also recommend using a custom hasher with similar API to the Crypto class. Crypto has a hardcoded iteration count with a rather small value.
Comments
There could be many ways of doing it..
I ideally I would mark the password property with a custom attribute name [Encrypt(true)]. So then when the property is saving to the database, you got to track the models property that marked by Encrypt attribute separately (inside DbContext Saving event). Then you could encrypt that and save it to the database inside the said saving event.
A custom attribute and a generic solution like this could come handy when you want to encrypt any other sensitive data that you want to save in to your database later too.
5 Comments
Decrypt operation. So how would you verify the a password with such a class? Password hashing APIs have two distinct operations to create and verify a hash. Creating a hash isn't deterministic, since it needs to generate a new salt.
Rfc2898DeriveBytesto implement an API similar to theCryptoclass, but with a higher iteration count.