key data, how to see expiration length?

Bobby
Bobby used Ask the Experts™
on
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.

BUT

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
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
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.
David FavorFractional CTO
Distinguished Expert 2018

Commented:
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.
David FavorFractional CTO
Distinguished Expert 2018

Commented:
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.
Expert Spotlight: Joe Anderson (DatabaseMX)

We’ve posted a new Expert Spotlight!  Joe Anderson (DatabaseMX) has been on Experts Exchange since 2006. Learn more about this database architect, guitar aficionado, and Microsoft MVP.

Author

Commented:
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.
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
Then either the decrypt is not working or the key is not present.

The code after line 8 expects a value in the form
CONTACTID:EXPIRES

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.

Author

Commented:
we upgraded about a month ago from php 5.5 to php 7.2
Most Valuable Expert 2017
Distinguished Expert 2018

Commented:
Well - that is your problem isn't it.
From here http://php.net/manual/en/function.mcrypt-decrypt.php
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

Author

Commented:
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.
Most Valuable Expert 2017
Distinguished Expert 2018
Commented:
You either need to convert to a different encryption library
OR
Change your impelementation - I suggest the unguessable unique key (UUID) in a DB table linked to a create time and an ID.

Your validation process then uses the key received to lookup the record.
Record must exist and current time - create time < expire period
If all good - proceed else fail
Delete the record from the table.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial