I think the was that session ids are generated is not very random. And this is concealed because of a layer of function calls that all look very good. Please follow me on the code path:
Let's start at Session::newSession https://github.com/OWASP/phpsec/blob/master/libs/session/session.php#L101
As you can see, there is a call to the function random(32)
, which promises to deliver 32 random characters.
That function https://github.com/OWASP/phpsec/blob/master/libs/core/random.php#L25 is only a simple proxy and forwards the call to Rand::randStr(32).
Now that function https://github.com/OWASP/phpsec/blob/master/libs/core/random.php#L109 actually does something: It grabs some randomness, hashes it into a string of finite length (which would lead to the whole functions so far to NOT deliver e.g. a random string of 2048 characters without hint or error - bad in itself, but not my point).
Ok, randomness... We do see a call to Rand::randRange() https://github.com/OWASP/phpsec/blob/master/libs/core/random.php#L87 with default parameters. This function does some checks, probably reverses $min
and $max
, grabs some randomness and then simply scales that into the range given. The range for default parameters is $min=0, $max = 2^31. So whatever the random generator delivers, it will here be reduced to 31 bits of randomness.
And the random number generator is in Rand::random() https://github.com/OWASP/phpsec/blob/master/libs/core/random.php#L47 itself has no parameters. In an ideal situation, the very good random function openssl_random_pseudo_bytes()
would be asked for FOUR bytes of randomness, which equals 32 bits. In absence of this function, the very bad random generator mt_rand()
would only issue 31 bits of randomness.
All in all, the session ids generated by this code will only contain 31 bits of randomness, packed into a nice looking substring of SHA512, suggesting much more randomness being included (SHA512 itself is 128 hex chars long, leaving room for 64 bytes of randomness instead of only 4 bytes).
Even the PHP default session id hash has /* maximum 15+19+19+10 bytes */
= 63 bytes of pseudo-randomness and not-that-easy-to-guess information - and this is criticized as "attackable" by some. (see https://github.com/php/php-src/blob/master/ext/session/session.c#L309)
What are good sources of randomness? I think a good example is given in the random salt generation of the password_hash library: https://github.com/ircmaxell/password_compat/blob/master/lib/password.php#L84
Plenty of sources are being asked, in the hope to find some good randomness:
mcrypt_create_iv()
, openssl_random_pseudo_bytes()
, fopen('/dev/urandom', 'r')
- and only then, as a last resort, mt_rand()
with as many calls as there should be bytes in the salt string.