Merge pull request #6940 from kinglozzer/randomgenerator

Only use random_bytes() for RandomGenerator (closes #6397)
This commit is contained in:
Damian Mooyman 2017-05-22 10:29:55 +12:00 committed by GitHub
commit 4197090e11
3 changed files with 27 additions and 60 deletions

View File

@ -21,6 +21,7 @@
"league/flysystem": "~1.0.12", "league/flysystem": "~1.0.12",
"monolog/monolog": "~1.11", "monolog/monolog": "~1.11",
"nikic/php-parser": "^2 || ^3", "nikic/php-parser": "^2 || ^3",
"paragonie/random_compat": "^2.0",
"silverstripe/config": "^1@dev", "silverstripe/config": "^1@dev",
"silverstripe/assets": "^1@dev", "silverstripe/assets": "^1@dev",
"swiftmailer/swiftmailer": "~5.4", "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 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). * 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.) * 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. * Required modules: dom, gd2, fileinfo, hash, iconv, mbstring, mysqli (or other database driver), session, simplexml, tokenizer, xml.
* Recommended configuration * Recommended configuration

View File

@ -2,75 +2,31 @@
namespace SilverStripe\Security; namespace SilverStripe\Security;
use Error;
use Exception; use Exception;
/** /**
* Generates entropy values based on strongest available methods * Convenience class for generating cryptographically secure pseudo-random strings/tokens
* (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
*/ */
class RandomGenerator class RandomGenerator
{ {
/** /**
* Note: Returned values are not guaranteed to be crypto-safe, * @return string A 128-character, randomly generated ASCII string
* depending on the used retrieval method. * @throws Exception If no suitable CSPRNG is installed
*
* @return string Returns a random series of bytes
*/ */
public function generateEntropy() public function generateEntropy()
{ {
$isWin = preg_match('/WIN/', PHP_OS);
// PHP 7.1 preference, since mcrypt is deprecated
if (function_exists('random_bytes')) {
return bin2hex(random_bytes(64));
}
// 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 { try {
$comObj = new \COM('CAPICOM.Utilities.1'); return bin2hex(random_bytes(64));
} catch (Error $e) {
if (is_callable(array($comObj,'GetRandom'))) { throw $e; // This is required so that Error exceptions in PHP 5 aren't caught below
return base64_decode($comObj->GetRandom(64, 0)); } 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/'
);
} }
} 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 * 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. * in the database as a plain text but encrypt it with Member::encryptWithUserSettings.
* *
* @param String $algorithm Any identifier listed in hash_algos() (Default: whirlpool) * @param string $algorithm Any identifier listed in hash_algos() (Default: whirlpool)
* * @return string Returned length will depend on the used $algorithm
* @return String Returned length will depend on the used $algorithm
*/ */
public function randomToken($algorithm = 'whirlpool') public function randomToken($algorithm = 'whirlpool')
{ {