Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cause hash to expire after a certain time

Tags:

security

php

hash

I have a situation where a script receives some data from the user, it then returns a hash. For a certain amount of time, say X seconds, the hash is valid and when supplied back to the script along with the original data and within the specified timeframe, certain functions are allowed to be accessed.

I am doing this by including a timestamp in the hash. I can get a timestamp by calling say floor(time()/X); but this, instead of expiring after X seconds, expires anywhere between 1 and X seconds. I have got around this by saving time()%X and appending it to the hash, then when I receive it back, parsing it out and subtracting it from time(), so my hash function looks a little like this:

function hash($oldhash='') {
    static $hash;
    if(!$hash) {
        $time = time();
        $expoff = explode('!', $oldhash, 2); 
        $expoff = $expoff[0] ? $expoff[0] : $time%$this->_cfg['hashexpire'];
        $hash = $expoff.'!'.sha1($this->_data.floor(($time-$expoff)/$this->_cfg['hashexpire']));
    }   
    return $hash;
}

Theres also a salt in there but i removed it for clarity.

This works, but I'm thinking there is probably a better way to achieve what I am after here and wonder if you have any suggestions.

like image 525
tjm Avatar asked May 17 '11 20:05

tjm


2 Answers

Well, you want it to expire after a certain number of seconds, correct? Well, why not pre-compute the expire time, and pass that instead? You're only talking a few extra bytes being transferred:

function makeHash() {
    $expire = time() + $this->_cfg['hashexpire'];
    $hash = $expire . ':' . hash_hmac('sha1', $this->_data, $expire);
    return $hash;
}

Then to verify:

function verifyHash($hash) {
     if(!strpos($hash, ':')) return false;
     list ($expire, $rawhash) = explode(':', $hash, 2);
     $testhash = hash_hmac('sha1', $this->_data, $expire);
     if ($expire < time() && $testhash == $rawhash) {
         return true;
     }
     return false;
}

Note that it's using a HMAC to "sign" the data payload.

And if you're really paranoid about the data size, just base_convert($expire, 10, 36) prior to sending it to the client, and then decode it when verifying it.

Edit: As I'm rereading your question, I'm not sure. Are you looking for a hash to be generated that will be invalid after $x seconds? Or are you looking to generate the same hash for a absolute time window of $x seconds (after which the hash changes)? If the prior, the above solution will work. If the later, then you could try something like this:

function makeHash() {
    $time = time();
    $startTime = $time - ($time % $this->_cfg['hashexpire']);
    return hash_hmac('sha1', $this->_data, $startTime);
}

The reason this works, is that it hashes with the timestamp of the first valid second of the present window. That will always stay the same, so there's no need to store it or go any farther...

Note that the generated hash will change only every $_cfg['hashexpire'] seconds. But it could be invalidated the very second after it was created. So only use this if that's really what you need. }

like image 187
ircmaxell Avatar answered Sep 23 '22 14:09

ircmaxell


Since you tagged this with security, appending the time to the hash and extracting it isn't very secure. An attacker can reverse your code and provide a different timestamp. You need a way (like a database or flat file construction on your server) to associate the hash with a timestamp that the user cannot modify.

Another option is to encrypt the timestamp with a password in your code, so that even if the user extracts the timestamp part she will be unable to encrypt the new timestamp. If you meant this with 'salt', it wasn't clear in your question if you salted the hash or the timestamp.

like image 37
Mel Avatar answered Sep 25 '22 14:09

Mel