md5(uniqid) makes sense for random unique tokens?

65,805

Solution 1

rand() is a security hazard and should never be used to generate a security token: rand() vs mt_rand() (Look at the "static" like images). But neither of these methods of generating random numbers is cryptographically secure. To generate secure secerts an application will needs to access a CSPRNG provided by the platform, operating system or hardware module.

In a web application a good source for secure secrets is non-blocking access to an entropy pool such as /dev/urandom. As of PHP 5.3, PHP applications can use openssl_random_pseudo_bytes(), and the Openssl library will choose the best entropy source based on your operating system, under Linux this means the application will use /dev/urandom. This code snip from Scott is pretty good:

function crypto_rand_secure($min, $max) {
        $range = $max - $min;
        if ($range < 0) return $min; // not so random...
        $log = log($range, 2);
        $bytes = (int) ($log / 8) + 1; // length in bytes
        $bits = (int) $log + 1; // length in bits
        $filter = (int) (1 << $bits) - 1; // set all lower bits to 1
        do {
            $rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
            $rnd = $rnd & $filter; // discard irrelevant bits
        } while ($rnd >= $range);
        return $min + $rnd;
}

function getToken($length=32){
    $token = "";
    $codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    $codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
    $codeAlphabet.= "0123456789";
    for($i=0;$i<$length;$i++){
        $token .= $codeAlphabet[crypto_rand_secure(0,strlen($codeAlphabet))];
    }
    return $token;
}

Solution 2

This is a copy of another question I found that was asked a few months before this one. Here is a link to the question and my answer: https://stackoverflow.com/a/13733588/1698153.

I do not agree with the accepted answer. According to PHPs own website "[uniqid] does not generate cryptographically secure tokens, in fact without being passed any additional parameters the return value is little different from microtime(). If you need to generate cryptographically secure tokens use openssl_random_pseudo_bytes()."

I do not think the answer could be clearer than this, uniqid is not secure.

Solution 3

I know the question is old, but it shows up in Google, so...

As others said, rand(), mt_rand() or uniqid() will not guarantee you uniqueness... even openssl_random_pseudo_bytes() should not be used, since it uses deprecated features of OpenSSL.

What you should use to generate random hash (same as md5) is random_bytes() (introduced in PHP7). To generate hash with same length as MD5:

bin2hex(random_bytes(16));

If you are using PHP 5.x you can get this function by including random_compat library.

Solution 4

Define "unique". If you mean that two tokens cannot have the same value, then hashing isn't enough - it should be backed with a uniqueness test. The fact that you supply the hash algorithm with unique inputs does not guarantee unique outputs.

Solution 5

To answer your question, the problem is you can't have a generator that is guaranteed random and unique as random by itself, i.e., md5(mt_rand()) can lead to duplicates. What you want is "random appearing" unique values. uniqid gives the unique id, rand() affixes a random number making it even harder to guess, md5 masks the result to make it yet even harder to guess. Nothing is unguessable. We just need to make it so hard that they wouldn't even want to try.

Share:
65,805
Exception e
Author by

Exception e

Updated on April 18, 2020

Comments

  • Exception e
    Exception e about 4 years

    I want to create a token generator that generates tokens that cannot be guessed by the user and that are still unique (to be used for password resets and confirmation codes).

    I often see this code; does it make sense?

    md5(uniqid(rand(), true));
    

    According to a comment uniqid($prefix, $moreEntopy = true) yields

    first 8 hex chars = Unixtime, last 5 hex chars = microseconds.

    I don't know how the $prefix-parameter is handled..

    So if you don't set the $moreEntopy flag to true, it gives a predictable outcome.


    QUESTION: But if we use uniqid with $moreEntopy, what does hashing it with md5 buy us? Is it better than:

    md5(mt_rand())
    

    edit1: I will store this token in an database column with a unique index, so I will detect columns. Might be of interest/