Ideally we can add a Config variable, that defaults to false, that prevents the use of the last two random number generators (Capicom for Windows and mt_rand()) unless the config var is changed to true, so it is opt-in to produce non-psuedo-random numbers.
Probably a v4 change given it would change the output of the method (might throw an Exception where none was thrown before).
Are there any tangible risks to how it is at the moment?
The method comment states * Note: Returned values are not guaranteed to be crypto-safe,. This method should not be used in any place where it could potentially raise a security risk at all.
I would rather see this left in place, and we implemented a proper crypto-safe random number generator instead. php 5.5 (supported in 4.0) has better crypto-random generation.
Sort of related - Function mcrypt_create_iv() is deprecated in framework/src/Security/RandomGenerator.php:30 during a module's Travis build on PHP 7.1. If we want to support 7.1 for SS 4 we'll probably need to replace it.
Regarding dropping the deprecated (in 7.1) mcrypt library use, here is the RFC that drops it (for reference). It seems that the suitable replacement would be openssl_random_pseudo_bytes' which is already implemented in this method, just a lower priority thanmcrypt_create_iv`.
I propose we simply remove the mcrypt use, leave the rest and give a higher priority for Windows to the method that @tractorcow shared over the existing code. Personally, I don't see any reason why we shouldn't remove old Windows code now (4.x) in favour of more modern, cross platform methods.
I've modularised a bit and given openssl priority over mcrypt in this commit - some feedback would be appreciated in the new year. It's possibly not necessary to modularise, but I figured it would be worthwhile in the long run to reduce some function complexity.
@robbieaverill from a quick look that commit looks good - but is there a thirdparty library we can use that does the same thing?
https://github.com/ircmaxell/RandomLib this looks good, well maintained and regularly contributed to
@dhensby yeah cool. As long as we are ok with replacing the functionality with a new backend essentially then I'll have a play with that instead
Damn - @dhensby - looks like that module isn't 7.1 compatible yet (ref: ircmaxell/RandomLib#55). It's definitely worth implementing though.
hmmm - it's not so much it doesn't work, just that it's relying on deprecated libs - that's a shame, but maybe not a show stopper?
I've removed my suggestion because it wasn't a correct secure random number generator.
PHP 7 has random_bytes, but of course we can't rely on this without bumping our minimum version to php7.
However, with combination of mcrypt_* being deprecated in php 7.1 onwards, and random_bytes being available from 7.0 onwards, we have at least a complete surface area that doesn't require us to add any new dependencies. :)
Note that random_bytes is documented as being cryptographically secure.
@tractorcow How about random_bytes() + https://github.com/paragonie/random_compat?
This part concerns me a little:
If PHP cannot safely generate random data, this library will throw an Exception. It will never fall back to insecure random data. If this keeps happening, upgrade to a newer version of PHP immediately.
Can we ensure that we NEVER get an exception thrown with only the bare minimum of server dependencies installed? Otherwise we either need to bump our requirements or look for an alternative.
IMO the best solution is to remove the RandomGenerator class entirely, and simply error on systems that don鈥檛 support random_bytes() or the polyfill. For the polyfill, the randomness sources are well documented so we could update our server requirements if we really want to. It doesn鈥檛 do anything drastically different to our currently implementation though (besides the removal of openssl_random_pseudo_bytes(), and _not_ falling back to mt_rand() - both of which are good things).
In the case of PHP 7, I鈥檇 like to think that it鈥檚 safe to assume that if it ships with PHP, it鈥檒l be very well supported - but I can鈥檛 find anything to back that up! For reference, this is what the native function currently checks: https://github.com/php/php-src/blob/c8aa6f3a9a3d2c114d0c5e0c9fdd0a465dbb54a5/ext/standard/random.c#L84-L184.
Yeah but I think we need to do better for our users than "you'll get an error if you aren't configured properly." What they'll need to know is what to do to ensure that doesn't happen at all. Otherwise they could end up with errors in a live environment they didn't expect. I'd factor what that is before choosing to adopt this library.
PHP 7 should be fine, I'm mostly concerned about 5.x
So to summarise, the requirements/order sources are checked are:
RandomGenerator class:random_bytes() (PHP 7 only, no polyfill)mcrypt_create_iv()openssl_random_pseudo_bytes()/dev/urandom (Linux / BSD only)CAPICOM.Utilities.1 (Windows only)mt_rand()random_bytes():/dev/urandom (Linux / BSD only)mcrypt_create_iv() (which on Windows will try to read from CryptGenRandom)CAPICOM.Utilities.1 (Windows only)random_bytes():CryptGenRandom (Windows only)arc4random_buf (OpenBSD/NetBSD only)getrandom(2) (Linux only)/dev/urandomgetrandom(2) is available but fails, it will throw an exception immediately rather than fall back to /dev/urandom)Would that info in the server requirements doc suffice? We could even catch the exceptions that random_bytes() throws and provide our own message to point people in the right direction.
@kinglozzer worth noting that my recent PR adds priority for random bytes before mcrypt
@kinglozzer I think that's fine. ;)