Fixes #9878,9879,9880: Make `\base\Security` use `random_bytes()`, LibreSSL, mcrypt, limit OpenSSL to Windows, and to prefer `password_hash()` over `crypt()`
tags/2.0.7
Tom Worster9 years agocommitted byAlexander Makarov
- Chg #9953:`TimestampBehavior::getValue()` changed to make value processing consistent with `AttributeBehavior::getValue()` (silverfire)
- Chg #9953:`TimestampBehavior::getValue()` changed to make value processing consistent with `AttributeBehavior::getValue()` (silverfire)
- Chg #6419: Added `yii\web\ErrorHandler::displayVars` make list of displayed vars customizable. `$_ENV` and `$_SERVER` are not displayed by default anymore (silverfire)
- Chg #6419: Added `yii\web\ErrorHandler::displayVars` make list of displayed vars customizable. `$_ENV` and `$_SERVER` are not displayed by default anymore (silverfire)
- Chg #9528: Traversable objects are now formatted as arrays in `yii\web\XmlResponseFormatter` to support SPL objects and Generators (MaXL-ru)
- Chg #9528: Traversable objects are now formatted as arrays in `yii\web\XmlResponseFormatter` to support SPL objects and Generators (MaXL-ru)
- Chg #9878,9879,9880: Make `\base\Security` use `random_bytes()`, LibreSSL, mcrypt, limit OpenSSL to Windows, and to prefer `password_hash()` over `crypt()` (tom--)
- Chg #10296: Methods mset, mget and madd of `\yii\caching\Cache` have been marked as deprecated (trejder, githubjeka)
- Chg #10296: Methods mset, mget and madd of `\yii\caching\Cache` have been marked as deprecated (trejder, githubjeka)
- Chg: ApcCache is now able to handle PHP 7 APCu (samdark)
- Chg: ApcCache is now able to handle PHP 7 APCu (samdark)
- New #10083: Added wrapper for PHP webserver (samdark)
- New #10083: Added wrapper for PHP webserver (samdark)
'openssl_random_pseudo_bytes() set $crypto_strong false. Your PHP setup is insecure.'
);
}
if ($key !== false && StringHelper::byteLength($key) === $length) {
$this->_randomSource = 'OpenSSL';
return $key;
}
$this->_randomSource = null;
}
throw new Exception('Unable to generate a random key');
}
}
/**
/**
@ -507,6 +574,14 @@ class Security extends Component
*/
*/
public function generateRandomString($length = 32)
public function generateRandomString($length = 32)
{
{
if (!is_int($length)) {
throw new InvalidParamException('First parameter ($length) must be an integer');
}
if ($length <1){
throw new InvalidParamException('First parameter ($length) must be greater than 0');
}
$bytes = $this->generateRandomKey($length);
$bytes = $this->generateRandomKey($length);
// '=' character(s) returned by base64_encode() are always discarded because
// '=' character(s) returned by base64_encode() are always discarded because
// they are guaranteed to be after position $length in the base64_encode() output.
// they are guaranteed to be after position $length in the base64_encode() output.
@ -553,24 +628,19 @@ class Security extends Component
$cost = $this->passwordHashCost;
$cost = $this->passwordHashCost;
}
}
switch ($this->passwordHashStrategy) {
if (function_exists('password_hash')) {
case 'password_hash':
if (!function_exists('password_hash')) {
throw new InvalidConfigException('Password hash key strategy "password_hash" requires PHP >= 5.5.0, either upgrade your environment or use another strategy.');
// strlen() is safe since crypt() returns only ascii
// strlen() is safe since crypt() returns only ascii
if (!is_string($hash) || strlen($hash) !== 60) {
if (!is_string($hash) || strlen($hash) !== 60) {
throw new Exception('Unknown error occurred while generating hash.');
throw new Exception('Unknown error occurred while generating hash.');
}
}
return $hash;
return $hash;
default:
throw new InvalidConfigException("Unknown password hash strategy '{$this->passwordHashStrategy}'");
}
}
}
/**
/**
@ -588,26 +658,24 @@ class Security extends Component
throw new InvalidParamException('Password must be a string and cannot be empty.');
throw new InvalidParamException('Password must be a string and cannot be empty.');
}
}
if (!preg_match('/^\$2[axy]\$(\d\d)\$[\.\/0-9A-Za-z]{22}/', $hash, $matches) || $matches[1] <4||$matches[1]> 30) {
if (!preg_match('/^\$2[axy]\$(\d\d)\$[\.\/0-9A-Za-z]{22}/', $hash, $matches)
|| $matches[1] <4
|| $matches[1] > 30
) {
throw new InvalidParamException('Hash is invalid.');
throw new InvalidParamException('Hash is invalid.');
}
}
switch ($this->passwordHashStrategy) {
if (function_exists('password_verify')) {
case 'password_hash':
if (!function_exists('password_verify')) {
throw new InvalidConfigException('Password hash key strategy "password_hash" requires PHP >= 5.5.0, either upgrade your environment or use another strategy.');
}
return password_verify($password, $hash);
return password_verify($password, $hash);
case 'crypt':
}
$test = crypt($password, $hash);
$test = crypt($password, $hash);
$n = strlen($test);
$n = strlen($test);
if ($n !== 60) {
if ($n !== 60) {
return false;
return false;
}
}
return $this->compareString($test, $hash);
return $this->compareString($test, $hash);
default:
throw new InvalidConfigException("Unknown password hash strategy '{$this->passwordHashStrategy}'");