I am looking to implement a Forgot Password feature on my website. I like the option where an email containing a temporary one-time use URL that expires after some time is sent
I used a Hashing Class to create unique automatic logins made up of the current date/time and the users email address:
string strNow = DateTime.Now.ToString();
string strHash = strNow + strEmail;
strHash = Hash.GetHash(strHash, Hash.HashType.SHA1);
get the Hash Class from: http://www.developerfusion.com/code/4601/create-hashes-md5-sha1-sha256-sha384-sha512/
Then just take it from the URL using:
if (Request.QueryString["hash"] != null)
{
//extract Hash from the URL
string strHash = Request.QueryString["hash"];
}
I'd use a hash code to validate details in the password reset url. This can all be done without writing anything to the DB or sending any privileged info to an attaker.
To briefly explain normal password salt and hashing; say the salt is 1111
and the pasword is password
, you'd concatenate the two and hash the string 1111password
, say this gives you a hash of 9999
, you'd then store the original salt 1111
and hash 9999
in your user record.
When you are validating a password you use the stored salt, concatenate the password attempt, hash it and compare with the stored hash. For example asecret
becomes 1111asecret
but hashes to 8888
. This doesn't match the original hash so the password match fails.
Of course the salt and hash would normally be properly generated and calculated with established crypto libraries (don't invent your own!).
For the password reset URL I'd put in the unique identifier for the user, i.e. email address, the date the request is made, and a new hash. This hash would be generated from those details concatenated together plus the salt and hash already stored for the user.
For example:
Email: user@example.com
Request Date: 2014-07-17
Salt: 1111
Hash: 9999
Generate a new hash of those concatenated, i.e. 'user@example.com2014-07-1711119999'
, say this gives a hash of 7777
.
The URL I then generate would then have the email, request date and the new hash:
https:\\www.example.com\ResetPassword?email=user@example.com&requestdate=2014-07-17&hash=7777
The server will combine the email and supplied date with it's salt and hash and confirm the hash it generated is the same as the supplied one. If this is Ok then it will show the reset form with the same three parameters hidden behind it, otherwise an error. These get resubmitted and rechecked when the new password is entered to prevent that form being spoofed.
The email address needs to be supplied to make the request and it is only sent out in an email to the same address. the date is hardly priveleged info and the hash is not reversible so gives nothing anyway. Nothing has been written to the database and any tampering with the parameters causes the hash to fail and the URL to report an error.
There is an issues with this approach. A safe hash makes the token really long. Either you integrate the salt into the hash itself (makes it about 20 charactes longer), or you store this unique salt in the database. If you store the salt in the database, you could as well store a random token which is not derrived from any existing