I wondered how to recover the user's password, but without using the database to store the generated hash for the password recovery link. It’s also impossible to store the hash in any other way .

From the basic conditions:

  1. The link is valid only for the current email and user password (more precisely for the password hash, because only it is stored in the database)

  2. Link valid only for 24 hours after creation

If there were no second item, then it would be possible to simply generate in some way a hash from the current mail and user password + add some secret characters from the server side, and then check which hash the user gave.

But what about the second item? If you substitute a time stamp in the hash, it will not work.

    3 answers 3

    I think that in any way. Let me explain why: 1) all static sources of data storage, such as writing hashes to a file, can be considered a kind of base, here you can use soap. 2) It may be suitable for you to record in the session, which is not safe in the first place, and not practical in the second. Since the user can make a request from one computer, and follow the link from another. But if this is a type of problem with a uni, then it can be done this way, and the problem with the time out will be solved, just keep the session awake for 24 hours

    And if it's not difficult for you, explain, why do you need this bike?

    additions (after the author's comment)

    one godless crutch came to mind, it will work, provided that the user restores the password, and does not log in (because you can know the current password, and just click restore)

    Hash the entire line in the database + the start field of the password recovery process (we do not store a hash)

    After, when clicking on the link, we alternately hash all the lines in the database and compare each with the hash that arrived in the URL (if the user did not log in, then the line in the database did not change, that is, the hash will be the same), we find the matching, look in the database mark start vostanvleniya, compare with the current date (24 hours of the link) well, and do something if less than 24 hours have passed ...

    This is the logic

    • The question is not a practical component. The question was asked at the interview, I could not find a solution. But in the end they did not say how it could be realized, although they asserted confidently that there was a solution, now I wonder how. It’s impossible to store a hash anywhere, not in a database, not in a file, not in a session. We can only use data that is already in the database. Well, you need to fulfill 2 conditions described in the post. - Floyat
    • That's the problem. That you can not save the start of recovery mark, too. All we have is the current password of the user (or the hash in the database, it doesn't matter), the current email address of the user. We send the user a link that is valid 24 hours and must check whether it is really he and whether the link is valid (its parameters). There should be hashing, not encryption. - Floyat
    • OK, then in the link do an additional gett parameter with time - mydls1

    We take the data structure containing:

    1. email 2. TTL 3. Новый пароль 

    Encrypt it all - get a hash, give the user a hash

    Upon receipt of the hash - decrypt, check TTL and email, change password

    • The task does not imply decryption of the incoming hssh from the user. It needs only to be verified with its own (md5, sha, etc. similar algorithms), and not to be deciphered. Yes, and I think it is very unsafe. - Floyat
    • Although I like the solution from a more experienced user, I really like it! - mydls1

    I found a way out myself.

    Decision number 1. Not the best if the link is valid for more than a day.

     $email = 'email@mail.ru'; $hashPass = 'текущий_хэш_пароля_из_бд'; //хэш, который будет отправлен пользователю вместе с ссылкой $hash = md5($email.$hashPass.time()); echo "http://mysite.ru/restore?hash=".$hash.'<br>'; //так будет выглядеть проверка корректности хэша $time = time(); for ($i = 0; $i <= 86400; $i++){ if ($hash === md5($email.$hashPass.($time - $i))){ echo 'Хэш совпадает!'; break; } } 

    Decision number 2. With symmetric encryption.

     function base64_url_encode($input) { return strtr(base64_encode($input), '+/=', '-_,'); } function base64_url_decode($input) { return base64_decode(strtr($input, '-_,', '+/=')); } function my_encode($data,$key,$iv){ $enc = $data.openssl_encrypt(time(), "AES-128-CBC", $key, OPENSSL_RAW_DATA, $iv); return base64_url_encode($enc); } function my_decode($data,$key,$iv){ $enc = openssl_decrypt($data, "AES-128-CBC", $key, OPENSSL_RAW_DATA, $iv); return $enc; } $appCodeKey = '16CodeKeySymbols'; //Initialization Vector для openssl_encrypt/openssl_decrypt $email = 'email@mail.ru'; $hashPass = 'текущий_хэш_пароля_из_бд'; //md5 для примера, можно изменить на другие более криптостойкие алгоритмы $key = md5($email); $hash = md5($email.$hashPass); $encode = my_encode($hash,$key,$appCodeKey); echo "http://mysite.ru/restore?hash=".$encode.'<br>'; //проверка корректности хэша $decode = base64_url_decode($encode,$key,$appCodeKey); $dec_hash = substr($decode,0,32); $dec_time = my_decode(substr($decode,32),$key,$appCodeKey); if ($dec_hash === $hash && $dec_time >= time() - 86400){ echo 'Корректный хэш'; } 

    Surely, it is possible to change or change something, it is not necessary to hash it in the second variant or send an email in the clear, by the second parameter.

    Decision number 3.

     $ts = strtotime("+1 day"); $link = "http://mysite.ru/restore?email=".urlencode($email)."&ts=$ts&hash=".md5($pass_hash.$email.$ts); 

    The essence of the problem was in theory, and not in the practical component. It will work. This is what I wanted to achieve.