Personally, I don't worry about the seeding problem. The chances are that unless you're releasing the code, the attacker won't know the exact sequence of your random number generation, so it's exceptionally hard for them to brute force predict the next number. And consider the use case of the number you're using. I'm assuming that they are for temporary passwords. So if you're worried about brute forcing random numbers that much, I assume that you've added a system to disable logins from a single host after a certain number of failures (so if someone tried 10 times incorrectly from the same host, you auto-ban that host for a time period). Sure, it doesn't stop the DDOS attack, but it should make brute forcing MUCH more difficult.
And the number generation issue (the seeding issue) is really only a major issue in one of a few scenarios:
- You don't control all of the code on the server (meaning non-trusted users can install their own code which is served by the same php process)
- You output the number directly (instead of using it for an internal calculation with other inputs)
- You're using CGI
Other than that, I'd think you'd be relatively safe with seeding with something along the lines of (Only if you fall into one of the 3 above categories):
$seed = crc32(uniqid(sha1(microtime(true) . getmypid()), true));
mt_srand($seed);
$n = mt_rand(1, 200);
for ($i = 0; $i < $n; $i++) {
mt_rand();
}
then simply using mt_rand to return the number you want.
The rational is as such:
$seed = crc32(uniqid(sha1(microtime(true) . getmypid()), true));
From the inside out, you're generating a value for the current microsecond, and then passing it through sha1 to get a string. Then you're passing that through uniqid which will add 23 bits of entropy to that figure. CRC32 is used to turn the resultant string into a number for seeding mt_srand();
$n = mt_rand(1, 200);
for ($i = 0; $i < $n; $i++) {
mt_rand();
}
Even if someone figures out the value of a mt_rand call that you use later on in the code, they won't know which call it was (so it makes it a lot harder to figure out which sequence you're using). Without that part, if they saw a 4, they'd only need to check the first 2 or 3 positions of known seed sequences to try to "guess" the next value. With this part, they have no idea at the initial value, nor the actual position in the sequence that you're at, so it becomes a non-trivial problem to search the list for a match in the sequence.
But again, if you're running your own server, I wouldn't worry too much about it. Spend your time with a secure hash salting algorythm and guarding against brute force attacks, and you'll be fine...