Only use random_bytes() for RandomGenerator (closes #6397)

This commit is contained in:
Loz Calver 2017-05-19 11:18:56 +01:00
parent 41a268c69f
commit e653e90997
3 changed files with 27 additions and 60 deletions

View File

@ -21,6 +21,7 @@
"league/flysystem": "~1.0.12",
"monolog/monolog": "~1.11",
"nikic/php-parser": "^2 || ^3",
"paragonie/random_compat": "^2.0",
"silverstripe/config": "^1@dev",
"silverstripe/assets": "^1@dev",
"swiftmailer/swiftmailer": "~5.4",

View File

@ -13,6 +13,17 @@ Our web-based [PHP installer](installation/) can check if you meet the requireme
we drop support for those versions in the [next minor release](/contributing/release-process). This means that PHP 5.6 support may be dropped in a 4.x minor release after December 2018.
* We recommend using a PHP accelerator or opcode cache, such as [xcache](http://xcache.lighttpd.net/) or [WinCache](http://www.iis.net/download/wincacheforphp).
* Allocate at least 48MB of memory to each PHP process. (SilverStripe can be resource hungry for some intensive operations.)
* PHP requires a suitable CSPRNG (random number generator) source for generating random tokens, password salts etc. This can be any of the following, and most operating systems will have at least one source available:
* PHP 7 `random_bytes()`:
* `CryptGenRandom` (Windows only)
* `arc4random_buf` (OpenBSD & NetBSD only)
* `getrandom(2)` (Linux only)
* `/dev/urandom`
* PHP 5 [`random_compat`](https://github.com/paragonie/random_compat) polyfill:
* libsodium
* `/dev/urandom`
* [`mcrypt_create_iv()`](http://php.net/manual/en/function.mcrypt-create-iv.php)
* CAPICOM Utilities (`CAPICOM.Utilities.1`, Windows only)
* Required modules: dom, gd2, fileinfo, hash, iconv, mbstring, mysqli (or other database driver), session, simplexml, tokenizer, xml.
* Recommended configuration

View File

@ -2,75 +2,31 @@
namespace SilverStripe\Security;
use Error;
use Exception;
/**
* Generates entropy values based on strongest available methods
* (mcrypt_create_iv(), openssl_random_pseudo_bytes(), /dev/urandom, COM.CAPICOM.Utilities.1, mt_rand()).
* Chosen method depends on operating system and PHP version.
*
* @author Ingo Schommer
* Convenience class for generating cryptographically secure pseudo-random strings/tokens
*/
class RandomGenerator
{
/**
* Note: Returned values are not guaranteed to be crypto-safe,
* depending on the used retrieval method.
*
* @return string Returns a random series of bytes
* @return string A 128-character, randomly generated ASCII string
* @throws Exception If no suitable CSPRNG is installed
*/
public function generateEntropy()
{
$isWin = preg_match('/WIN/', PHP_OS);
// PHP 7.1 preference, since mcrypt is deprecated
if (function_exists('random_bytes')) {
try {
return bin2hex(random_bytes(64));
} catch (Error $e) {
throw $e; // This is required so that Error exceptions in PHP 5 aren't caught below
} catch (Exception $e) {
throw new Exception(
'It appears there is no suitable CSPRNG (random number generator) installed. '
. 'Please review the server requirements documentation: '
. 'https://docs.silverstripe.org/en/getting_started/server_requirements/'
);
}
// TODO Fails with "Could not gather sufficient random data" on IIS, temporarily disabled on windows
if (!$isWin) {
if (function_exists('mcrypt_create_iv')) {
$e = mcrypt_create_iv(64, MCRYPT_DEV_URANDOM);
if ($e !== false) {
return $e;
}
}
}
// Fall back to SSL methods - may slow down execution by a few ms
if (function_exists('openssl_random_pseudo_bytes')) {
$e = openssl_random_pseudo_bytes(64, $strong);
// Only return if strong algorithm was used
if ($strong) {
return $e;
}
}
// Read from the unix random number generator
if (!$isWin && !ini_get('open_basedir') && is_readable('/dev/urandom') && ($h = fopen('/dev/urandom', 'rb'))) {
$e = fread($h, 64);
fclose($h);
return $e;
}
// Warning: Both methods below are considered weak
// try to read from the windows RNG
if ($isWin && class_exists('COM')) {
try {
$comObj = new \COM('CAPICOM.Utilities.1');
if (is_callable(array($comObj,'GetRandom'))) {
return base64_decode($comObj->GetRandom(64, 0));
}
} catch (Exception $ex) {
}
}
// Fallback to good old mt_rand()
return uniqid(mt_rand(), true);
}
/**
@ -80,9 +36,8 @@ class RandomGenerator
* If you are using it as a password equivalent (e.g. autologin token) do NOT store it
* in the database as a plain text but encrypt it with Member::encryptWithUserSettings.
*
* @param String $algorithm Any identifier listed in hash_algos() (Default: whirlpool)
*
* @return String Returned length will depend on the used $algorithm
* @param string $algorithm Any identifier listed in hash_algos() (Default: whirlpool)
* @return string Returned length will depend on the used $algorithm
*/
public function randomToken($algorithm = 'whirlpool')
{