I am implementing a password reset feature for a web application and am contemplating adopting an implementation similar to Django.
In a nutshell, Django creates a token who is comprised of a timestamp and a hash of the timestamp and the User ID. This hash is a HMAC and is used to verify that neither the timestamp or the user ID have been tampered with.
In addition to the timestamp, information about the user such as her password salt are hashed. This way, if the user changes her password, the token will become invalid, reducing the window of opportunity for an attacker.
The source code for the token generator can be viewed here and here is the pseudocode:
function make_token(user) timestamp = current timestamp (now) value = timestamp + user.id + user.password hash = create_hmac("some secret", value) return timestamp + ":" + hash function check_token(user, token) timestamp = token.split(":") hash = token.split(":") if timestamp is after expiration date return false value = timestamp + user.id + user.password comparate = create_hmac("some secret", value) // if the hash has changed, the token has been tampered with or the user has // changed their password. if hash != comparate return false return true
This seems like a good solution to me. Websites running Django have been doing this since 2008 or so and I cannot find any reports of a vulnerability.
I did some research and someone on Hacker News did not like this approach. There are also a couple of tickets on the subject that express concern. However, I am yet to find a specific reason as to why this is might be insecure.
Is this a secure approach to generating password reset tokens? If not, why?