Link to home
Start Free TrialLog in
Avatar of Bobby
BobbyFlag for United States of America

asked on

key data, how to see expiration length?

The following code is supposed to determine how long it has been since a password reset request was submitted. If the request has expired, disallow.

        } else if(!empty($request->get('key'))) {
          $dbAccessor = new DbAccessor();
          $new_password = $request->get('new_password');
          $rawkey = $dbAccessor->unobfuscate_id($request->get('key'));
          $keyparts = explode(":", $rawkey);
          $contact_id = $keyparts[0];
          $expiration = $keyparts[1];

          if(time() > $expiration) {
             $redirect = "/account/reset_my_password?error=key_expired";

Open in new window

I know it works, because I changed the > to a < in the if(time() > $expiration), and I could not reset my password.

I'm a complete newb at this, taking over for a staff member who moved away. He was our main back end web dev, and Im scrambling to fill his shoes as much as I can.

I was tasked with this because somebody ran across a link that was sent out to a real customer months ago to reset their password. We clicked the link, and it took us to the password reset page, as if it was perfectly fine to reset our password after all those months. The link should have expired.


This may have been designed so that the user doesn't get a message that it has expired, it just doesnt do what it says (like my test in reversing the <>). That would be perfectly acceptable... not graceful, but at least the password could not be reset via that link 3 months later.

So... obviously I need to figure out the value of this: $keyparts[1]; to see what time value is being specified (if any). How do I see that? Here is the unobfuscate_id function:

   public function unobfuscate_id($str) {  
      $key = "realdatastripped";
      $encrypted_str = base64_decode(str_pad(strtr($str, '-_', '+/'), strlen($str) % 4, '=', STR_PAD_RIGHT));
      $str = mcrypt_decrypt(MCRYPT_DES, $key, $encrypted_str, MCRYPT_MODE_ECB);
      $block = mcrypt_get_block_size('des', 'ecb');
      $pad = ord($str[($len = strlen($str)) - 1]);
      $unencrypted_str = substr($str, 0, strlen($str) - $pad);
      return str_replace("dm", "", $unencrypted_str);

Open in new window

If it helps, here is the key in one email I initiated to myself for a password request: reset_my_password?key=XPLDFLhFhu0O192aM6dmCGhW4srTDUQw
Avatar of Julian Hansen
Julian Hansen
Flag of South Africa image

mcrypt functions have been deprecated.
Trying to run that code gives a warning
Key of size 16 not supported by this algorithm. Only keys of size 8 supported
There is a way to convert to opnessl but it is taking too much time.
Can you add the following to your code (line 8 - or anywhere after line 4).
echo "<pre>" . print_r($rawkey, true) . "</pre>";

Open in new window

Post the results here.

This is a very complicated solution. Another option is just to generate a UUID() (if you are using MySQL or MariaDB you can do it with the UUID() function).
Save this to an activation key table in the DB with a timestamp and userid.
When a key comes in compare timestamp to current time() - if outside expiry period then deny.

Cleanup script runs regularly to clean up table.

The nice thing about this approach is that no information is stored in the key.
The key can't be tampered with.
You can change the expiry time and it will apply to all existing keys.
Julian is correct, mcrypt has been deprecated. Use libsodium instead.

Also, as Julian said, fixing this will be complex.

My guess is you'll have to fix your code to use libsodium or another supported encryption type.

Once your code is working, this should trigger every user doing a password reset.

Depending on your database table schema, you may also have to run an alter table to change your password field length.

Also version of PHP you're running on today + version your upgrading to will be a factor.
Since you said, "I'm a complete newb at this" likely best if you hire someone to help you with this.

Also, keep the PHP Compatibility Checker URL handy, as this tool is a must for finding other potential problems in your code which are near impossible to catch by eye.

Also, if your code has a debugging facility, enable it so all problems are logged instantly.

If your code has no debugging facility, this will be one of the first tasks you complete, so you can see all errors/warnings, rather than guess.
Avatar of Bobby


Julian, I added

echo "<pre>" . print_r($rawkey, true) . "</pre>";

where you said but it does not print to the browser, so I have no results to post.
Then either the decrypt is not working or the key is not present.

The code after line 8 expects a value in the form

If you are not seeing this then the extract of the key is not working.

What version of PHP are you using?

Seriously, I would move away from an encrypted solution - in my view it only complicates your solution. A simple unguessable key (like UUID) linked to database record would work much better.
Avatar of Bobby


we upgraded about a month ago from php 5.5 to php 7.2
Well - that is your problem isn't it.
From here
This function has been DEPRECATED as of PHP 7.1.0 and REMOVED as of PHP 7.2.0. Relying on this function is highly discouraged.
Your code is never going to work because the mcrypt functions have been removedin 7.2
Avatar of Bobby


Ugh. Thanks for researching. So, in a nutshell, what do you think our quickest solution will be? I need to take this to the CEO and give him some kind of timeline to getting it fixed.
Avatar of Julian Hansen
Julian Hansen
Flag of South Africa image

Link to home
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial