mirror of
https://github.com/yiisoft/yii2.git
synced 2025-08-26 14:26:54 +08:00
Finished cookie.
Finished SecurityHelper.
This commit is contained in:
@ -298,14 +298,6 @@ class Application extends Module
|
||||
date_default_timezone_set($value);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Returns the security manager component.
|
||||
// * @return SecurityManager the security manager application component.
|
||||
// */
|
||||
// public function getSecurityManager()
|
||||
// {
|
||||
// return $this->getComponent('securityManager');
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * Returns the locale instance.
|
||||
|
@ -1,290 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* SecurityManager class file.
|
||||
*
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright © 2008 Yii Software LLC
|
||||
* @license http://www.yiiframework.com/license/
|
||||
*/
|
||||
|
||||
namespace yii\base;
|
||||
|
||||
/**
|
||||
* SecurityManager provides private keys, hashing and encryption functions.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @since 2.0
|
||||
*/
|
||||
class SecurityManager extends Component
|
||||
{
|
||||
const STATE_VALIDATION_KEY = 'Yii.SecurityManager.validationkey';
|
||||
const STATE_ENCRYPTION_KEY = 'Yii.SecurityManager.encryptionkey';
|
||||
|
||||
/**
|
||||
* @var string the name of the hashing algorithm to be used by {@link computeHMAC}.
|
||||
* See {@link http://php.net/manual/en/function.hash-algos.php hash-algos} for the list of possible
|
||||
* hash algorithms. Note that if you are using PHP 5.1.1 or below, you can only use 'sha1' or 'md5'.
|
||||
*
|
||||
* Defaults to 'sha1', meaning using SHA1 hash algorithm.
|
||||
*/
|
||||
public $hashAlgorithm = 'sha1';
|
||||
/**
|
||||
* @var mixed the name of the crypt algorithm to be used by {@link encrypt} and {@link decrypt}.
|
||||
* This will be passed as the first parameter to {@link http://php.net/manual/en/function.mcrypt-module-open.php mcrypt_module_open}.
|
||||
*
|
||||
* This property can also be configured as an array. In this case, the array elements will be passed in order
|
||||
* as parameters to mcrypt_module_open. For example, <code>array('rijndael-256', '', 'ofb', '')</code>.
|
||||
*
|
||||
* Defaults to 'des', meaning using DES crypt algorithm.
|
||||
*/
|
||||
public $cryptAlgorithm = 'des';
|
||||
|
||||
private $_validationKey;
|
||||
private $_encryptionKey;
|
||||
|
||||
/**
|
||||
* @return string a randomly generated private key
|
||||
*/
|
||||
protected function generateRandomKey()
|
||||
{
|
||||
return sprintf('%08x%08x%08x%08x', mt_rand(), mt_rand(), mt_rand(), mt_rand());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the private key used to generate HMAC.
|
||||
* If the key is not explicitly set, a random one is generated and returned.
|
||||
*/
|
||||
public function getValidationKey()
|
||||
{
|
||||
if ($this->_validationKey !== null) {
|
||||
return $this->_validationKey;
|
||||
} else {
|
||||
if (($key = \Yii::$app->getGlobalState(self::STATE_VALIDATION_KEY)) !== null) {
|
||||
$this->setValidationKey($key);
|
||||
} else {
|
||||
$key = $this->generateRandomKey();
|
||||
$this->setValidationKey($key);
|
||||
\Yii::$app->setGlobalState(self::STATE_VALIDATION_KEY, $key);
|
||||
}
|
||||
return $this->_validationKey;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value the key used to generate HMAC
|
||||
* @throws CException if the key is empty
|
||||
*/
|
||||
public function setValidationKey($value)
|
||||
{
|
||||
if (!empty($value)) {
|
||||
$this->_validationKey = $value;
|
||||
} else {
|
||||
throw new CException(Yii::t('yii|SecurityManager.validationKey cannot be empty.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the private key used to encrypt/decrypt data.
|
||||
* If the key is not explicitly set, a random one is generated and returned.
|
||||
*/
|
||||
public function getEncryptionKey()
|
||||
{
|
||||
if ($this->_encryptionKey !== null) {
|
||||
return $this->_encryptionKey;
|
||||
} else {
|
||||
if (($key = \Yii::$app->getGlobalState(self::STATE_ENCRYPTION_KEY)) !== null) {
|
||||
$this->setEncryptionKey($key);
|
||||
} else {
|
||||
$key = $this->generateRandomKey();
|
||||
$this->setEncryptionKey($key);
|
||||
\Yii::$app->setGlobalState(self::STATE_ENCRYPTION_KEY, $key);
|
||||
}
|
||||
return $this->_encryptionKey;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value the key used to encrypt/decrypt data.
|
||||
* @throws CException if the key is empty
|
||||
*/
|
||||
public function setEncryptionKey($value)
|
||||
{
|
||||
if (!empty($value)) {
|
||||
$this->_encryptionKey = $value;
|
||||
} else {
|
||||
throw new CException(Yii::t('yii|SecurityManager.encryptionKey cannot be empty.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method has been deprecated since version 1.1.3.
|
||||
* Please use {@link hashAlgorithm} instead.
|
||||
* @return string
|
||||
*/
|
||||
public function getValidation()
|
||||
{
|
||||
return $this->hashAlgorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method has been deprecated since version 1.1.3.
|
||||
* Please use {@link hashAlgorithm} instead.
|
||||
* @param string $value -
|
||||
*/
|
||||
public function setValidation($value)
|
||||
{
|
||||
$this->hashAlgorithm = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts data.
|
||||
* @param string $data data to be encrypted.
|
||||
* @param string $key the decryption key. This defaults to null, meaning using {@link getEncryptionKey EncryptionKey}.
|
||||
* @return string the encrypted data
|
||||
* @throws CException if PHP Mcrypt extension is not loaded
|
||||
*/
|
||||
public function encrypt($data, $key = null)
|
||||
{
|
||||
$module = $this->openCryptModule();
|
||||
$key = $this->substr($key === null ? md5($this->getEncryptionKey()) : $key, 0, mcrypt_enc_get_key_size($module));
|
||||
srand();
|
||||
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND);
|
||||
mcrypt_generic_init($module, $key, $iv);
|
||||
$encrypted = $iv . mcrypt_generic($module, $data);
|
||||
mcrypt_generic_deinit($module);
|
||||
mcrypt_module_close($module);
|
||||
return $encrypted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts data
|
||||
* @param string $data data to be decrypted.
|
||||
* @param string $key the decryption key. This defaults to null, meaning using {@link getEncryptionKey EncryptionKey}.
|
||||
* @return string the decrypted data
|
||||
* @throws CException if PHP Mcrypt extension is not loaded
|
||||
*/
|
||||
public function decrypt($data, $key = null)
|
||||
{
|
||||
$module = $this->openCryptModule();
|
||||
$key = $this->substr($key === null ? md5($this->getEncryptionKey()) : $key, 0, mcrypt_enc_get_key_size($module));
|
||||
$ivSize = mcrypt_enc_get_iv_size($module);
|
||||
$iv = $this->substr($data, 0, $ivSize);
|
||||
mcrypt_generic_init($module, $key, $iv);
|
||||
$decrypted = mdecrypt_generic($module, $this->substr($data, $ivSize, $this->strlen($data)));
|
||||
mcrypt_generic_deinit($module);
|
||||
mcrypt_module_close($module);
|
||||
return rtrim($decrypted, "\0");
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the mcrypt module with the configuration specified in {@link cryptAlgorithm}.
|
||||
* @return resource the mycrypt module handle.
|
||||
* @since 1.1.3
|
||||
*/
|
||||
protected function openCryptModule()
|
||||
{
|
||||
if (extension_loaded('mcrypt')) {
|
||||
if (is_array($this->cryptAlgorithm)) {
|
||||
$module = @call_user_func_array('mcrypt_module_open', $this->cryptAlgorithm);
|
||||
} else {
|
||||
$module = @mcrypt_module_open($this->cryptAlgorithm, '', MCRYPT_MODE_CBC, '');
|
||||
}
|
||||
|
||||
if ($module === false) {
|
||||
throw new CException(Yii::t('yii|Failed to initialize the mcrypt module.'));
|
||||
}
|
||||
|
||||
return $module;
|
||||
} else {
|
||||
throw new CException(Yii::t('yii|SecurityManager requires PHP mcrypt extension to be loaded in order to use data encryption feature.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefixes data with an HMAC.
|
||||
* @param string $data data to be hashed.
|
||||
* @param string $key the private key to be used for generating HMAC. Defaults to null, meaning using {@link validationKey}.
|
||||
* @return string data prefixed with HMAC
|
||||
*/
|
||||
public function hashData($data, $key = null)
|
||||
{
|
||||
return $this->computeHMAC($data, $key) . $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates if data is tampered.
|
||||
* @param string $data data to be validated. The data must be previously
|
||||
* generated using {@link hashData()}.
|
||||
* @param string $key the private key to be used for generating HMAC. Defaults to null, meaning using {@link validationKey}.
|
||||
* @return string the real data with HMAC stripped off. False if the data
|
||||
* is tampered.
|
||||
*/
|
||||
public function validateData($data, $key = null)
|
||||
{
|
||||
$len = $this->strlen($this->computeHMAC('test'));
|
||||
if ($this->strlen($data) >= $len) {
|
||||
$hmac = $this->substr($data, 0, $len);
|
||||
$data2 = $this->substr($data, $len, $this->strlen($data));
|
||||
return $hmac === $this->computeHMAC($data2, $key) ? $data2 : false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the HMAC for the data with {@link getValidationKey ValidationKey}.
|
||||
* @param string $data data to be generated HMAC
|
||||
* @param string $key the private key to be used for generating HMAC. Defaults to null, meaning using {@link validationKey}.
|
||||
* @return string the HMAC for the data
|
||||
*/
|
||||
protected function computeHMAC($data, $key = null)
|
||||
{
|
||||
if ($key === null) {
|
||||
$key = $this->getValidationKey();
|
||||
}
|
||||
|
||||
if (function_exists('hash_hmac')) {
|
||||
return hash_hmac($this->hashAlgorithm, $data, $key);
|
||||
}
|
||||
|
||||
if (!strcasecmp($this->hashAlgorithm, 'sha1')) {
|
||||
$pack = 'H40';
|
||||
$func = 'sha1';
|
||||
} else {
|
||||
$pack = 'H32';
|
||||
$func = 'md5';
|
||||
}
|
||||
if ($this->strlen($key) > 64) {
|
||||
$key = pack($pack, $func($key));
|
||||
}
|
||||
if ($this->strlen($key) < 64) {
|
||||
$key = str_pad($key, 64, chr(0));
|
||||
}
|
||||
$key = $this->substr($key, 0, 64);
|
||||
return $func((str_repeat(chr(0x5C), 64) ^ $key) . pack($pack, $func((str_repeat(chr(0x36), 64) ^ $key) . $data)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the given string.
|
||||
* If available uses the multibyte string function mb_strlen.
|
||||
* @param string $string the string being measured for length
|
||||
* @return int the length of the string
|
||||
*/
|
||||
private function strlen($string)
|
||||
{
|
||||
return function_exists('mb_strlen') ? mb_strlen($string, '8bit') : strlen($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the portion of string specified by the start and length parameters.
|
||||
* If available uses the multibyte string function mb_substr
|
||||
* @param string $string the input string. Must be one character or longer.
|
||||
* @param int $start the starting position
|
||||
* @param int $length the desired portion length
|
||||
* @return string the extracted part of string, or FALSE on failure or an empty string.
|
||||
*/
|
||||
private function substr($string, $start, $length)
|
||||
{
|
||||
return function_exists('mb_substr') ? mb_substr($string, $start, $length, '8bit') : substr($string, $start, $length);
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* PasswordHelper class file.
|
||||
* SecurityHelper class file.
|
||||
*
|
||||
* @link http://www.yiiframework.com/
|
||||
* @copyright Copyright © 2008 Yii Software LLC
|
||||
@ -9,65 +9,37 @@
|
||||
|
||||
namespace yii\util;
|
||||
|
||||
use Yii;
|
||||
use yii\base\Exception;
|
||||
use yii\base\InvalidConfigException;
|
||||
use yii\base\InvalidParamException;
|
||||
|
||||
/**
|
||||
* PasswordHelper provides a simple API for secure password hashing and verification.
|
||||
* SecurityHelper provides a set of methods to handle common security-related tasks.
|
||||
*
|
||||
* PasswordHelper uses the Blowfish hash algorithm available in many PHP runtime
|
||||
* environments through the PHP [crypt()](http://php.net/manual/en/function.crypt.php)
|
||||
* built-in function. As of Dec 2012 it is the strongest algorithm available in PHP
|
||||
* and the only algorithm without some security concerns surrounding it. For this reason,
|
||||
* PasswordHelper fails to initialize when run in and environment that does not have
|
||||
* crypt() and its Blowfish option. Systems with the option include:
|
||||
* In particular, SecurityHelper supports the following features:
|
||||
*
|
||||
* 1. Most *nix systems since PHP 4 (the algorithm is part of the library function crypt(3));
|
||||
* 2. All PHP systems since 5.3.0;
|
||||
* 3. All PHP systems with the [Suhosin patch](http://www.hardened-php.net/suhosin/).
|
||||
* - Encryption/decryption: [[encrypt()]] and [[decrypt()]]
|
||||
* - Data tampering prevention: [[hashData()]] and [[validateData()]]
|
||||
* - Password validation: [[generatePasswordHash()]] and [[validatePassword()]]
|
||||
*
|
||||
* For more information about password hashing, crypt() and Blowfish, please read
|
||||
* the Yii Wiki article [Use crypt() for password storage](http://www.yiiframework.com/wiki/425/use-crypt-for-password-storage/)
|
||||
* and the PHP RFC [Adding simple password hashing API](http://wiki.php.net/rfc/password_hash).
|
||||
*
|
||||
* PasswordHelper throws an exception if the Blowfish hash algorithm is not
|
||||
* available in the runtime PHP's crypt() function. It can be used as follows
|
||||
*
|
||||
* Generate a hash from a password:
|
||||
*
|
||||
* ~~~
|
||||
* $hash = PasswordHelper::hashPassword($password);
|
||||
* ~~~
|
||||
*
|
||||
* This hash can be stored in a database (e.g. `CHAR(64) CHARACTER SET latin1` on MySQL). The
|
||||
* hash is usually generated and saved to the database when the user enters a new password.
|
||||
* But it can also be useful to generate and save a hash after validating a user's
|
||||
* password in order to change the cost or refresh the salt.
|
||||
*
|
||||
* To verify a password, fetch the user's saved hash from the database (into `$hash`) and:
|
||||
*
|
||||
* ~~~
|
||||
* if (PasswordHelper::verifyPassword($password, $hash) {
|
||||
* // password is good
|
||||
* } else {
|
||||
* // password is bad
|
||||
* }
|
||||
* ~~~
|
||||
* Additionally, SecurityHelper provides [[getSecretKey()]] to support generating
|
||||
* named secret keys. These secret keys, once generated, will be stored in a file
|
||||
* and made available in future requests.
|
||||
*
|
||||
* @author Qiang Xue <qiang.xue@gmail.com>
|
||||
* @author Tom Worster <fsb@thefsb.org>
|
||||
* @since 2.0
|
||||
*/
|
||||
|
||||
class PasswordHelper
|
||||
class SecurityHelper
|
||||
{
|
||||
|
||||
/**
|
||||
* Encrypts data.
|
||||
* @param string $data data to be encrypted.
|
||||
* @param string $key the encryption secret key
|
||||
* @return string the encrypted data
|
||||
* @throws Exception if PHP Mcrypt extension is not loaded or failed to be initialized
|
||||
* @see decrypt()
|
||||
*/
|
||||
public static function encrypt($data, $key)
|
||||
{
|
||||
@ -88,6 +60,7 @@ class PasswordHelper
|
||||
* @param string $key the decryption secret key
|
||||
* @return string the decrypted data
|
||||
* @throws Exception if PHP Mcrypt extension is not loaded or failed to be initialized
|
||||
* @see encrypt()
|
||||
*/
|
||||
public static function decrypt($data, $key)
|
||||
{
|
||||
@ -103,36 +76,69 @@ class PasswordHelper
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefixes data with an HMAC.
|
||||
* @param string $data data to be hashed.
|
||||
* @param string $key the private key to be used for generating HMAC. Defaults to null, meaning using {@link validationKey}.
|
||||
* @return string data prefixed with HMAC
|
||||
* Prefixes data with a keyed hash value so that it can later be detected if it is tampered.
|
||||
* @param string $data the data to be protected
|
||||
* @param string $key the secret key to be used for generating hash
|
||||
* @param string $algorithm the hashing algorithm (e.g. "md5", "sha1", "sha256", etc.). Call PHP "hash_algos()"
|
||||
* function to see the supported hashing algorithms on your system.
|
||||
* @return string the data prefixed with the keyed hash
|
||||
* @see validateData()
|
||||
* @see getSecretKey()
|
||||
*/
|
||||
public static function hashData($data, $key)
|
||||
public static function hashData($data, $key, $algorithm = 'sha256')
|
||||
{
|
||||
return hash_hmac('sha1', $data, $key) . $data;
|
||||
return hash_hmac($algorithm, $data, $key) . $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates if data is tampered.
|
||||
* @param string $data data to be validated. The data must be previously
|
||||
* generated using {@link hashData()}.
|
||||
* @param string $key the private key to be used for generating HMAC. Defaults to null, meaning using {@link validationKey}.
|
||||
* @return string the real data with HMAC stripped off. False if the data
|
||||
* is tampered.
|
||||
* Validates if the given data is tampered.
|
||||
* @param string $data the data to be validated. The data must be previously
|
||||
* generated by [[hashData()]].
|
||||
* @param string $key the secret key that was previously used to generate the hash for the data in [[hashData()]].
|
||||
* @param string $algorithm the hashing algorithm (e.g. "md5", "sha1", "sha256", etc.). Call PHP "hash_algos()"
|
||||
* function to see the supported hashing algorithms on your system. This must be the same
|
||||
* as the value passed to [[hashData()]] when generating the hash for the data.
|
||||
* @return string the real data with the hash stripped off. False if the data is tampered.
|
||||
* @see hashData()
|
||||
*/
|
||||
public function validateData($data, $key = null)
|
||||
public static function validateData($data, $key, $algorithm = 'sha256')
|
||||
{
|
||||
$len = $this->strlen($this->computeHMAC('test'));
|
||||
if ($this->strlen($data) >= $len) {
|
||||
$hmac = $this->substr($data, 0, $len);
|
||||
$data2 = $this->substr($data, $len, $this->strlen($data));
|
||||
return $hmac === $this->computeHMAC($data2, $key) ? $data2 : false;
|
||||
$hashSize = StringHelper::strlen(hash_hmac($algorithm, 'test', $key));
|
||||
$n = StringHelper::strlen($data);
|
||||
if ($n >= $hashSize) {
|
||||
$hash = StringHelper::substr($data, 0, $hashSize);
|
||||
$data2 = StringHelper::substr($data, $hashSize, $n - $hashSize);
|
||||
return $hash === hash_hmac($algorithm, $data2, $key) ? $data2 : false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a secret key associated with the specified name.
|
||||
* If the secret key does not exist, a random key will be generated
|
||||
* and saved in the file "keys.php" under the application's runtime directory
|
||||
* so that the same secret key can be returned in future requests.
|
||||
* @param string $name the name that is associated with the secret key
|
||||
* @param integer $length the length of the key that should be generated if not exists
|
||||
* @return string the secret key associated with the specified name
|
||||
*/
|
||||
public static function getSecretKey($name, $length = 32)
|
||||
{
|
||||
static $keys;
|
||||
$keyFile = Yii::$app->getRuntimePath() . '/keys.php';
|
||||
if ($keys === null) {
|
||||
$keys = is_file($keyFile) ? require($keyFile) : array();
|
||||
}
|
||||
if (!isset($keys[$name])) {
|
||||
// generate a 32-char random key
|
||||
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
$keys[$name] = substr(str_shuffle(str_repeat($chars, 5)), 0, $length);
|
||||
file_put_contents($keyFile, "<?php\nreturn " . var_export($keys, true) . ";\n");
|
||||
}
|
||||
return $keys[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the mcrypt module.
|
||||
* @return resource the mcrypt module handle.
|
||||
@ -144,7 +150,7 @@ class PasswordHelper
|
||||
if (!extension_loaded('mcrypt')) {
|
||||
throw new InvalidConfigException('The mcrypt PHP extension is not installed.');
|
||||
}
|
||||
$module = @mcrypt_module_open('des', '', MCRYPT_MODE_CBC, '');
|
||||
$module = @mcrypt_module_open('rijndael-256', '', MCRYPT_MODE_CBC, '');
|
||||
if ($module === false) {
|
||||
throw new Exception('Failed to initialize the mcrypt module.');
|
||||
}
|
||||
@ -152,10 +158,24 @@ class PasswordHelper
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a secure hash from a password and a random salt.
|
||||
* Generates a secure hash from a password and a random salt.
|
||||
*
|
||||
* Uses the PHP [crypt()](http://php.net/manual/en/function.crypt.php) built-in function
|
||||
* with the Blowfish hash option.
|
||||
* The generated hash can be stored in database (e.g. `CHAR(64) CHARACTER SET latin1` on MySQL).
|
||||
* Later when a password needs to be validated, the hash can be fetched and passed
|
||||
* to [[validatePassword()]]. For example,
|
||||
*
|
||||
* ~~~
|
||||
* // generates the hash (usually done during user registration or when the password is changed)
|
||||
* $hash = SecurityHelper::hashPassword($password);
|
||||
* // ...save $hash in database...
|
||||
*
|
||||
* // during login, validate if the password entered is correct using $hash fetched from database
|
||||
* if (PasswordHelper::verifyPassword($password, $hash) {
|
||||
* // password is good
|
||||
* } else {
|
||||
* // password is bad
|
||||
* }
|
||||
* ~~~
|
||||
*
|
||||
* @param string $password The password to be hashed.
|
||||
* @param integer $cost Cost parameter used by the Blowfish hash algorithm.
|
||||
@ -168,8 +188,9 @@ class PasswordHelper
|
||||
* 2^($cost - 14) seconds.
|
||||
* @throws Exception on bad password parameter or cost parameter
|
||||
* @return string The password hash string, ASCII and not longer than 64 characters.
|
||||
* @see validatePassword()
|
||||
*/
|
||||
public static function hashPassword($password, $cost = 13)
|
||||
public static function generatePasswordHash($password, $cost = 13)
|
||||
{
|
||||
$salt = static::generateSalt($cost);
|
||||
$hash = crypt($password, $salt);
|
||||
@ -187,8 +208,9 @@ class PasswordHelper
|
||||
* @param string $hash The hash to verify the password against.
|
||||
* @return boolean whether the password is correct.
|
||||
* @throws InvalidParamException on bad password or hash parameters or if crypt() with Blowfish hash is not available.
|
||||
* @see generatePasswordHash()
|
||||
*/
|
||||
public static function verifyPassword($password, $hash)
|
||||
public static function validatePassword($password, $hash)
|
||||
{
|
||||
if (!is_string($password) || $password === '') {
|
||||
throw new InvalidParamException('Password must be a string and cannot be empty.');
|
@ -11,6 +11,7 @@ namespace yii\web;
|
||||
|
||||
use Yii;
|
||||
use yii\base\DictionaryIterator;
|
||||
use yii\util\SecurityHelper;
|
||||
|
||||
/**
|
||||
* CookieCollection maintains the cookies available in the current request.
|
||||
@ -27,6 +28,10 @@ class CookieCollection extends \yii\base\Object implements \IteratorAggregate, \
|
||||
* if a cookie is tampered on the client side, it will be ignored when received on the server side.
|
||||
*/
|
||||
public $enableValidation = true;
|
||||
/**
|
||||
* @var string the secret key used for cookie validation. If not set, a random key will be generated and used.
|
||||
*/
|
||||
public $validationKey;
|
||||
|
||||
/**
|
||||
* @var Cookie[] the cookies in this collection (indexed by the cookie names)
|
||||
@ -111,7 +116,12 @@ class CookieCollection extends \yii\base\Object implements \IteratorAggregate, \
|
||||
|
||||
$value = $cookie->value;
|
||||
if ($this->enableValidation) {
|
||||
$value = Yii::$app->getSecurityManager()->hashData(serialize($value));
|
||||
if ($this->validationKey === null) {
|
||||
$key = SecurityHelper::getSecretKey(__CLASS__ . '/' . Yii::$app->id);
|
||||
} else {
|
||||
$key = $this->validationKey;
|
||||
}
|
||||
$value = SecurityHelper::hashData(serialize($value), $key);
|
||||
}
|
||||
|
||||
setcookie($cookie->name, $value, $cookie->expire, $cookie->path, $cookie->domain, $cookie->secure, $cookie->httpOnly);
|
||||
@ -205,7 +215,6 @@ class CookieCollection extends \yii\base\Object implements \IteratorAggregate, \
|
||||
$this->remove($name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current cookies in terms of [[Cookie]] objects.
|
||||
* @return Cookie[] list of current cookies
|
||||
@ -214,9 +223,13 @@ class CookieCollection extends \yii\base\Object implements \IteratorAggregate, \
|
||||
{
|
||||
$cookies = array();
|
||||
if ($this->enableValidation) {
|
||||
$sm = \Yii::$app->getSecurityManager();
|
||||
if ($this->validationKey === null) {
|
||||
$key = SecurityHelper::getSecretKey(__CLASS__ . '/' . Yii::$app->id);
|
||||
} else {
|
||||
$key = $this->validationKey;
|
||||
}
|
||||
foreach ($_COOKIE as $name => $value) {
|
||||
if (is_string($value) && ($value = $sm->validateData($value)) !== false) {
|
||||
if (is_string($value) && ($value = SecurityHelper::validateData($value, $key)) !== false) {
|
||||
$cookies[$name] = new Cookie(array(
|
||||
'name' => $name,
|
||||
'value' => @unserialize($value),
|
||||
|
@ -19,9 +19,13 @@ use yii\base\InvalidConfigException;
|
||||
class Request extends \yii\base\Request
|
||||
{
|
||||
/**
|
||||
* @var boolean whether cookies should be validated to ensure they are not tampered. Defaults to false.
|
||||
* @var boolean whether cookies should be validated to ensure they are not tampered. Defaults to true.
|
||||
*/
|
||||
public $enableCookieValidation = false;
|
||||
public $enableCookieValidation = true;
|
||||
/**
|
||||
* @var string the secret key used for cookie validation. If not set, a random key will be generated and used.
|
||||
*/
|
||||
public $cookieValidationKey;
|
||||
/**
|
||||
* @var boolean whether to enable CSRF (Cross-Site Request Forgery) validation. Defaults to false.
|
||||
* By setting this property to true, forms submitted to an Yii Web application must be originated
|
||||
@ -721,6 +725,7 @@ class Request extends \yii\base\Request
|
||||
if ($this->_cookies === null) {
|
||||
$this->_cookies = new CookieCollection(array(
|
||||
'enableValidation' => $this->enableCookieValidation,
|
||||
'validationKey' => $this->cookieValidationKey,
|
||||
));
|
||||
}
|
||||
return $this->_cookies;
|
||||
|
@ -70,12 +70,12 @@
|
||||
* @package system.web
|
||||
* @since 1.0
|
||||
*/
|
||||
class CHttpSession extends CApplicationComponent implements IteratorAggregate,ArrayAccess,Countable
|
||||
class CHttpSession extends CApplicationComponent implements IteratorAggregate, ArrayAccess, Countable
|
||||
{
|
||||
/**
|
||||
* @var boolean whether the session should be automatically started when the session application component is initialized, defaults to true.
|
||||
*/
|
||||
public $autoStart=true;
|
||||
public $autoStart = true;
|
||||
|
||||
|
||||
/**
|
||||
@ -85,9 +85,10 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
public function init()
|
||||
{
|
||||
parent::init();
|
||||
if($this->autoStart)
|
||||
if ($this->autoStart) {
|
||||
$this->open();
|
||||
register_shutdown_function(array($this,'close'));
|
||||
}
|
||||
register_shutdown_function(array($this, 'close'));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -109,18 +110,18 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
*/
|
||||
public function open()
|
||||
{
|
||||
if($this->getUseCustomStorage())
|
||||
@session_set_save_handler(array($this,'openSession'),array($this,'closeSession'),array($this,'readSession'),array($this,'writeSession'),array($this,'destroySession'),array($this,'gcSession'));
|
||||
if ($this->getUseCustomStorage()) {
|
||||
@session_set_save_handler(array($this, 'openSession'), array($this, 'closeSession'), array($this, 'readSession'), array($this, 'writeSession'), array($this, 'destroySession'), array($this, 'gcSession'));
|
||||
}
|
||||
|
||||
@session_start();
|
||||
if(YII_DEBUG && session_id()=='')
|
||||
{
|
||||
$message=Yii::t('yii|Failed to start session.');
|
||||
if(function_exists('error_get_last'))
|
||||
{
|
||||
$error=error_get_last();
|
||||
if(isset($error['message']))
|
||||
$message=$error['message'];
|
||||
if (YII_DEBUG && session_id() == '') {
|
||||
$message = Yii::t('yii|Failed to start session.');
|
||||
if (function_exists('error_get_last')) {
|
||||
$error = error_get_last();
|
||||
if (isset($error['message'])) {
|
||||
$message = $error['message'];
|
||||
}
|
||||
}
|
||||
Yii::log($message, CLogger::LEVEL_WARNING, 'system.web.CHttpSession');
|
||||
}
|
||||
@ -131,17 +132,17 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
if(session_id()!=='')
|
||||
if (session_id() !== '') {
|
||||
@session_write_close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees all session variables and destroys all data registered to a session.
|
||||
*/
|
||||
public function destroy()
|
||||
{
|
||||
if(session_id()!=='')
|
||||
{
|
||||
if (session_id() !== '') {
|
||||
@session_unset();
|
||||
@session_destroy();
|
||||
}
|
||||
@ -152,7 +153,7 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
*/
|
||||
public function getIsStarted()
|
||||
{
|
||||
return session_id()!=='';
|
||||
return session_id() !== '';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -177,7 +178,7 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
* @param boolean $deleteOldSession Whether to delete the old associated session file or not.
|
||||
* @since 1.1.8
|
||||
*/
|
||||
public function regenerateID($deleteOldSession=false)
|
||||
public function regenerateID($deleteOldSession = false)
|
||||
{
|
||||
session_regenerate_id($deleteOldSession);
|
||||
}
|
||||
@ -212,11 +213,12 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
*/
|
||||
public function setSavePath($value)
|
||||
{
|
||||
if(is_dir($value))
|
||||
if (is_dir($value)) {
|
||||
session_save_path($value);
|
||||
else
|
||||
} else {
|
||||
throw new CException(Yii::t('yii|CHttpSession.savePath "{path}" is not a valid directory.',
|
||||
array('{path}'=>$value)));
|
||||
array('{path}' => $value)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -237,13 +239,14 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
*/
|
||||
public function setCookieParams($value)
|
||||
{
|
||||
$data=session_get_cookie_params();
|
||||
$data = session_get_cookie_params();
|
||||
extract($data);
|
||||
extract($value);
|
||||
if(isset($httponly))
|
||||
session_set_cookie_params($lifetime,$path,$domain,$secure,$httponly);
|
||||
else
|
||||
session_set_cookie_params($lifetime,$path,$domain,$secure);
|
||||
if (isset($httponly)) {
|
||||
session_set_cookie_params($lifetime, $path, $domain, $secure, $httponly);
|
||||
} else {
|
||||
session_set_cookie_params($lifetime, $path, $domain, $secure);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -251,37 +254,39 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
*/
|
||||
public function getCookieMode()
|
||||
{
|
||||
if(ini_get('session.use_cookies')==='0')
|
||||
if (ini_get('session.use_cookies') === '0') {
|
||||
return 'none';
|
||||
else if(ini_get('session.use_only_cookies')==='0')
|
||||
} else {
|
||||
if (ini_get('session.use_only_cookies') === '0') {
|
||||
return 'allow';
|
||||
else
|
||||
} else {
|
||||
return 'only';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value how to use cookie to store session ID. Valid values include 'none', 'allow' and 'only'.
|
||||
*/
|
||||
public function setCookieMode($value)
|
||||
{
|
||||
if($value==='none')
|
||||
{
|
||||
ini_set('session.use_cookies','0');
|
||||
ini_set('session.use_only_cookies','0');
|
||||
}
|
||||
else if($value==='allow')
|
||||
{
|
||||
ini_set('session.use_cookies','1');
|
||||
ini_set('session.use_only_cookies','0');
|
||||
}
|
||||
else if($value==='only')
|
||||
{
|
||||
ini_set('session.use_cookies','1');
|
||||
ini_set('session.use_only_cookies','1');
|
||||
}
|
||||
else
|
||||
if ($value === 'none') {
|
||||
ini_set('session.use_cookies', '0');
|
||||
ini_set('session.use_only_cookies', '0');
|
||||
} else {
|
||||
if ($value === 'allow') {
|
||||
ini_set('session.use_cookies', '1');
|
||||
ini_set('session.use_only_cookies', '0');
|
||||
} else {
|
||||
if ($value === 'only') {
|
||||
ini_set('session.use_cookies', '1');
|
||||
ini_set('session.use_only_cookies', '1');
|
||||
} else {
|
||||
throw new CException(Yii::t('yii|CHttpSession.cookieMode can only be "none", "allow" or "only".'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return integer the probability (percentage) that the gc (garbage collection) process is started on every session initialization, defaults to 1 meaning 1% chance.
|
||||
@ -297,15 +302,14 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
*/
|
||||
public function setGCProbability($value)
|
||||
{
|
||||
$value=(int)$value;
|
||||
if($value>=0 && $value<=100)
|
||||
{
|
||||
ini_set('session.gc_probability',$value);
|
||||
ini_set('session.gc_divisor','100');
|
||||
}
|
||||
else
|
||||
$value = (int)$value;
|
||||
if ($value >= 0 && $value <= 100) {
|
||||
ini_set('session.gc_probability', $value);
|
||||
ini_set('session.gc_divisor', '100');
|
||||
} else {
|
||||
throw new CException(Yii::t('yii|CHttpSession.gcProbability "{value}" is invalid. It must be an integer between 0 and 100.',
|
||||
array('{value}'=>$value)));
|
||||
array('{value}' => $value)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -313,7 +317,7 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
*/
|
||||
public function getUseTransparentSessionID()
|
||||
{
|
||||
return ini_get('session.use_trans_sid')==1;
|
||||
return ini_get('session.use_trans_sid') == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -321,7 +325,7 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
*/
|
||||
public function setUseTransparentSessionID($value)
|
||||
{
|
||||
ini_set('session.use_trans_sid',$value?'1':'0');
|
||||
ini_set('session.use_trans_sid', $value ? '1' : '0');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -337,7 +341,7 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
*/
|
||||
public function setTimeout($value)
|
||||
{
|
||||
ini_set('session.gc_maxlifetime',$value);
|
||||
ini_set('session.gc_maxlifetime', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -348,7 +352,7 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
* @param string $sessionName session name
|
||||
* @return boolean whether session is opened successfully
|
||||
*/
|
||||
public function openSession($savePath,$sessionName)
|
||||
public function openSession($savePath, $sessionName)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -384,7 +388,7 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
* @param string $data session data
|
||||
* @return boolean whether session write is successful
|
||||
*/
|
||||
public function writeSession($id,$data)
|
||||
public function writeSession($id, $data)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -461,7 +465,7 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
* @return mixed the session variable value, or $defaultValue if the session variable does not exist.
|
||||
* @since 1.1.2
|
||||
*/
|
||||
public function get($key,$defaultValue=null)
|
||||
public function get($key, $defaultValue = null)
|
||||
{
|
||||
return isset($_SESSION[$key]) ? $_SESSION[$key] : $defaultValue;
|
||||
}
|
||||
@ -483,9 +487,9 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
* @param mixed $key session variable name
|
||||
* @param mixed $value session variable value
|
||||
*/
|
||||
public function add($key,$value)
|
||||
public function add($key, $value)
|
||||
{
|
||||
$_SESSION[$key]=$value;
|
||||
$_SESSION[$key] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -495,24 +499,24 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
*/
|
||||
public function remove($key)
|
||||
{
|
||||
if(isset($_SESSION[$key]))
|
||||
{
|
||||
$value=$_SESSION[$key];
|
||||
if (isset($_SESSION[$key])) {
|
||||
$value = $_SESSION[$key];
|
||||
unset($_SESSION[$key]);
|
||||
return $value;
|
||||
}
|
||||
else
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all session variables
|
||||
*/
|
||||
public function clear()
|
||||
{
|
||||
foreach(array_keys($_SESSION) as $key)
|
||||
foreach (array_keys($_SESSION) as $key) {
|
||||
unset($_SESSION[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $key session variable name
|
||||
@ -556,9 +560,9 @@ class CHttpSession extends CApplicationComponent implements IteratorAggregate,Ar
|
||||
* @param integer $offset the offset to set element
|
||||
* @param mixed $item the element value
|
||||
*/
|
||||
public function offsetSet($offset,$item)
|
||||
public function offsetSet($offset, $item)
|
||||
{
|
||||
$_SESSION[$offset]=$item;
|
||||
$_SESSION[$offset] = $item;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user