类 yii\base\Security
继承 | yii\base\Security » yii\base\Component » yii\base\BaseObject |
---|---|
实现 | yii\base\Configurable |
版本可用 | 2.0 |
源代码 | https://github.com/yiisoft/yii2/blob/master/framework/base/Security.php |
Security 提供了一组方法来处理常见的安全相关任务。
特别地,Security 支持以下功能
- 加密/解密: encryptByKey(), decryptByKey(), encryptByPassword() 和 decryptByPassword()
- 使用标准算法的密钥推导: pbkdf2() 和 hkdf()
- 数据篡改预防: hashData() 和 validateData()
- 密码验证: generatePasswordHash() 和 validatePassword()
注意: 此类需要 'OpenSSL' PHP 扩展才能在 Windows 上生成随机密钥/字符串,以及在所有平台上进行加密/解密。为了获得最高级别的安全性,建议使用 PHP 版本 >= 5.5.0。
有关 Security 的更多详细信息和使用信息,请参阅 安全指南文章。
公共属性
属性 | 类型 | 描述 | 定义 |
---|---|---|---|
$allowedCiphers | array[] | 每个支持的 OpenSSL 密码的块大小和密钥大小的查找表。 | yii\base\Security |
$authKeyInfo | string | 用于推导消息身份验证密钥的 HKDF 信息值。 | yii\base\Security |
$behaviors | yii\base\Behavior[] | 附加到此组件的行为列表。 | yii\base\Component |
$cipher | string | 用于加密和解密的密码。 | yii\base\Security |
$derivationIterations | integer | 推导迭代次数。 | yii\base\Security |
$kdfHash | string | 密钥推导的哈希算法。 | yii\base\Security |
$macHash | string | 消息身份验证的哈希算法。 | yii\base\Security |
$passwordHashCost | integer | 用于密码哈希的默认成本。 | yii\base\Security |
$passwordHashStrategy | string | 用于生成密码哈希的策略。 | yii\base\Security |
公共方法
受保护的方法
方法 | 描述 | 定义 |
---|---|---|
decrypt() | 解密 data。 | yii\base\Security |
encrypt() | 加密 data。 | yii\base\Security |
generateSalt() | 生成可用于生成密码哈希的盐。 | yii\base\Security |
shouldUseLibreSSL() | yii\base\Security |
属性详细信息
每个支持的 OpenSSL 密码的块大小和密钥大小的查找表。
在每个元素中,键是 OpenSSL 支持的密码之一(@see openssl_get_cipher_methods())。值是一个包含两个整数的数组,第一个是密码的块大小(以字节为单位),第二个是密钥大小(以字节为单位)。
警告: 我们推荐的所有 OpenSSL 密码都在默认值中,即 CBC 模式下的 AES。
注意: Yii 的加密协议对密码密钥、HMAC 签名密钥和密钥推导盐使用相同的大小。
'AES-128-CBC' => [
16,
16,
],
'AES-192-CBC' => [
16,
24,
],
'AES-256-CBC' => [
16,
32,
],
]
用于推导消息身份验证密钥的 HKDF 信息值。
另请参阅 hkdf().
密钥派生的哈希算法。推荐 sha256、sha384 或 sha512。
另请参阅 hash_algos().
消息认证的哈希算法。推荐 sha256、sha384 或 sha512。
另请参阅 hash_algos().
密码哈希使用的默认成本。允许的值在 4 到 31 之间。
另请参阅 generatePasswordHash().
password_hash()
(如果可用)或 crypt()
(如果不可用)。
应使用哪个策略来生成密码哈希。可用策略
- 'password_hash' - 使用 PHP
password_hash()
函数和 PASSWORD_DEFAULT 算法。此选项是推荐的,但它需要 PHP 版本 >= 5.5.0 - 'crypt' - 使用 PHP
crypt()
函数。
方法详情
定义于: yii\base\Component::__call()
调用不是类方法的命名方法。
此方法将检查是否有任何附加的行为具有命名的函数,如果有,将执行它。
不要直接调用此方法,因为它是 PHP 魔术方法,当调用未知函数时会隐式调用。
public mixed __call ( $name, $params ) | ||
$name | string |
函数名称 |
$params | array |
函数参数 |
返回值 | mixed |
函数返回值 |
---|---|---|
抛出异常 | yii\base\UnknownMethodException |
当调用未知函数时 |
public function __call($name, $params)
{
$this->ensureBehaviors();
foreach ($this->_behaviors as $object) {
if ($object->hasMethod($name)) {
return call_user_func_array([$object, $name], $params);
}
}
throw new UnknownMethodException('Calling unknown method: ' . get_class($this) . "::$name()");
}
public void __clone ( ) |
public function __clone()
{
$this->_events = [];
$this->_eventWildcards = [];
$this->_behaviors = null;
}
定义于: yii\base\BaseObject::__construct()
构造函数。
默认实现执行两件事
- 使用给定的配置
$config
初始化对象。 - 调用 init().
如果此方法在子类中被重写,建议
- 构造函数的最后一个参数是一个配置数组,如这里的
$config
。 - 在构造函数的末尾调用父实现。
public void __construct ( $config = [] ) | ||
$config | array |
将用于初始化对象属性的名称-值对 |
public function __construct($config = [])
{
if (!empty($config)) {
Yii::configure($this, $config);
}
$this->init();
}
定义于: yii\base\Component::__get()
返回组件属性的值。
此方法将按以下顺序检查并相应地采取行动
- 由 getter 定义的属性:返回 getter 结果
- 行为的属性:返回行为属性值
不要直接调用此方法,因为它是 PHP 魔术方法,在执行 $value = $component->property;
时会隐式调用。
另请参阅 __set().
public mixed __get ( $name ) | ||
$name | string |
属性名称 |
返回值 | mixed |
属性值或行为属性的值 |
---|---|---|
抛出异常 | yii\base\UnknownPropertyException |
如果未定义属性 |
抛出异常 | yii\base\InvalidCallException |
如果属性是只写。 |
public function __get($name)
{
$getter = 'get' . $name;
if (method_exists($this, $getter)) {
// read property, e.g. getName()
return $this->$getter();
}
// behavior property
$this->ensureBehaviors();
foreach ($this->_behaviors as $behavior) {
if ($behavior->canGetProperty($name)) {
return $behavior->$name;
}
}
if (method_exists($this, 'set' . $name)) {
throw new InvalidCallException('Getting write-only property: ' . get_class($this) . '::' . $name);
}
throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
}
定义于: yii\base\Component::__isset()
检查属性是否已设置,即已定义且不为空。
此方法将按以下顺序检查并相应地采取行动
- 由 setter 定义的属性:返回属性是否已设置
- 行为属性:返回属性是否已设置
- 对于不存在的属性返回
false
不要直接调用此方法,因为它是一个 PHP 魔术方法,在执行 isset($component->property)
时会被隐式调用。
public boolean __isset ( $name ) | ||
$name | string |
属性名或事件名 |
返回值 | boolean |
命名的属性是否已设置 |
---|
public function __isset($name)
{
$getter = 'get' . $name;
if (method_exists($this, $getter)) {
return $this->$getter() !== null;
}
// behavior property
$this->ensureBehaviors();
foreach ($this->_behaviors as $behavior) {
if ($behavior->canGetProperty($name)) {
return $behavior->$name !== null;
}
}
return false;
}
定义在: yii\base\Component::__set()
设置组件属性的值。
此方法将按以下顺序检查并相应地采取行动
- 由 setter 定义的属性:设置属性值
- "on xyz" 格式的事件:将处理程序附加到 "xyz" 事件
- "as xyz" 格式的行为:附加名为 "xyz" 的行为
- 行为的属性:设置行为属性值
不要直接调用此方法,因为它是一个 PHP 魔术方法,在执行 $component->property = $value;
时会被隐式调用。
另请参阅 __get()。
public void __set ( $name, $value ) | ||
$name | string |
属性名或事件名 |
$value | mixed |
属性值 |
抛出异常 | yii\base\UnknownPropertyException |
如果未定义属性 |
---|---|---|
抛出异常 | yii\base\InvalidCallException |
如果属性是只读的。 |
public function __set($name, $value)
{
$setter = 'set' . $name;
if (method_exists($this, $setter)) {
// set property
$this->$setter($value);
return;
} elseif (strncmp($name, 'on ', 3) === 0) {
// on event: attach event handler
$this->on(trim(substr($name, 3)), $value);
return;
} elseif (strncmp($name, 'as ', 3) === 0) {
// as behavior: attach behavior
$name = trim(substr($name, 3));
$this->attachBehavior($name, $value instanceof Behavior ? $value : Yii::createObject($value));
return;
}
// behavior property
$this->ensureBehaviors();
foreach ($this->_behaviors as $behavior) {
if ($behavior->canSetProperty($name)) {
$behavior->$name = $value;
return;
}
}
if (method_exists($this, 'get' . $name)) {
throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name);
}
throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name);
}
定义在: yii\base\Component::__unset()
将组件属性设置为 null。
此方法将按以下顺序检查并相应地采取行动
- 由 setter 定义的属性:将属性值设置为 null
- 行为的属性:将属性值设置为 null
不要直接调用此方法,因为它是一个 PHP 魔术方法,在执行 unset($component->property)
时会被隐式调用。
public void __unset ( $name ) | ||
$name | string |
属性名称 |
抛出异常 | yii\base\InvalidCallException |
如果属性是只读的。 |
---|
public function __unset($name)
{
$setter = 'set' . $name;
if (method_exists($this, $setter)) {
$this->$setter(null);
return;
}
// behavior property
$this->ensureBehaviors();
foreach ($this->_behaviors as $behavior) {
if ($behavior->canSetProperty($name)) {
$behavior->$name = null;
return;
}
}
throw new InvalidCallException('Unsetting an unknown or read-only property: ' . get_class($this) . '::' . $name);
}
定义在: yii\base\Component::attachBehavior()
将行为附加到此组件。
此方法将根据给定的配置创建行为对象。之后,行为对象将通过调用 yii\base\Behavior::attach() 方法附加到此组件。
另请参阅 detachBehavior()。
public yii\base\Behavior attachBehavior ( $name, $behavior ) | ||
$name | string |
行为的名称。 |
$behavior | string|array|yii\base\Behavior |
行为配置。它可以是以下之一:
|
返回值 | yii\base\Behavior |
行为对象 |
---|
public function attachBehavior($name, $behavior)
{
$this->ensureBehaviors();
return $this->attachBehaviorInternal($name, $behavior);
}
定义在: yii\base\Component::attachBehaviors()
将行为列表附加到组件。
每个行为都由其名称索引,并且应该是一个 yii\base\Behavior 对象,一个指定行为类的字符串,或者一个用于创建行为的配置数组。
另请参阅 attachBehavior()。
public void attachBehaviors ( $behaviors ) | ||
$behaviors | array |
要附加到组件的行为列表 |
public function attachBehaviors($behaviors)
{
$this->ensureBehaviors();
foreach ($behaviors as $name => $behavior) {
$this->attachBehaviorInternal($name, $behavior);
}
}
定义在: yii\base\Component::behaviors()
返回此组件应表现为的行为列表。
子类可以覆盖此方法以指定它们想要作为其行为的行为。
此方法的返回值应该是一个行为对象或配置数组,这些对象或配置由行为名称索引。行为配置可以是指定行为类的字符串,也可以是以下结构的数组
'behaviorName' => [
'class' => 'BehaviorClass',
'property1' => 'value1',
'property2' => 'value2',
]
请注意,行为类必须扩展自 yii\base\Behavior。行为可以使用名称或匿名方式附加。当名称用作数组键时,使用此名称,行为可以稍后使用 getBehavior() 检索,或使用 detachBehavior() 分离。匿名行为无法检索或分离。
在此方法中声明的行为将自动附加到组件(按需)。
public array behaviors ( ) | ||
返回值 | array |
行为配置。 |
---|
public function behaviors()
{
return [];
}
定义在: yii\base\Component::canGetProperty()
返回一个值,指示属性是否可以读取。
如果属性可以读取:
- 该类具有与指定名称关联的 getter 方法(在这种情况下,属性名称不区分大小写);
- 该类具有与指定名称相同的成员变量(当
$checkVars
为真时); - 附加的行为具有给定名称的可读属性(当
$checkBehaviors
为真时)。
另请参阅 canSetProperty()。
public boolean canGetProperty ( $name, $checkVars = true, $checkBehaviors = true ) | ||
$name | string |
属性名称 |
$checkVars | boolean |
是否将成员变量视为属性 |
$checkBehaviors | boolean |
是否将行为的属性视为此组件的属性 |
返回值 | boolean |
属性是否可以读取 |
---|
public function canGetProperty($name, $checkVars = true, $checkBehaviors = true)
{
if (method_exists($this, 'get' . $name) || $checkVars && property_exists($this, $name)) {
return true;
} elseif ($checkBehaviors) {
$this->ensureBehaviors();
foreach ($this->_behaviors as $behavior) {
if ($behavior->canGetProperty($name, $checkVars)) {
return true;
}
}
}
return false;
}
定义在: yii\base\Component::canSetProperty()
返回一个值,指示属性是否可以设置。
如果属性可以写入:
- 该类具有与指定名称关联的 setter 方法(在这种情况下,属性名称不区分大小写);
- 该类具有与指定名称相同的成员变量(当
$checkVars
为真时); - 附加的行为具有给定名称的可写属性(当
$checkBehaviors
为真时)。
另请参阅 canGetProperty()。
public boolean canSetProperty ( $name, $checkVars = true, $checkBehaviors = true ) | ||
$name | string |
属性名称 |
$checkVars | boolean |
是否将成员变量视为属性 |
$checkBehaviors | boolean |
是否将行为的属性视为此组件的属性 |
返回值 | boolean |
属性是否可以写入 |
---|
public function canSetProperty($name, $checkVars = true, $checkBehaviors = true)
{
if (method_exists($this, 'set' . $name) || $checkVars && property_exists($this, $name)) {
return true;
} elseif ($checkBehaviors) {
$this->ensureBehaviors();
foreach ($this->_behaviors as $behavior) {
if ($behavior->canSetProperty($name, $checkVars)) {
return true;
}
}
}
return false;
}
::class
代替。
定义在: yii\base\BaseObject::className()
返回此类的完全限定名称。
public static string className ( ) | ||
返回值 | string |
此类的完全限定名称。 |
---|
public static function className()
{
return get_called_class();
}
使用时间攻击抗性方法执行字符串比较。
public boolean compareString ( $expected, $actual ) | ||
$expected | string |
要比较的字符串。 |
$actual | string |
用户提供的字符串。 |
返回值 | boolean |
字符串是否相等。 |
---|
public function compareString($expected, $actual)
{
if (!is_string($expected)) {
throw new InvalidArgumentException('Expected expected value to be a string, ' . gettype($expected) . ' given.');
}
if (!is_string($actual)) {
throw new InvalidArgumentException('Expected actual value to be a string, ' . gettype($actual) . ' given.');
}
if (function_exists('hash_equals')) {
return hash_equals($expected, $actual);
}
$expected .= "\0";
$actual .= "\0";
$expectedLength = StringHelper::byteLength($expected);
$actualLength = StringHelper::byteLength($actual);
$diff = $expectedLength - $actualLength;
for ($i = 0; $i < $actualLength; $i++) {
$diff |= (ord($actual[$i]) ^ ord($expected[$i % $expectedLength]));
}
return $diff === 0;
}
解密 data。
另见 encrypt()。
protected boolean|string decrypt ( $data, $passwordBased, $secret, $info ) | ||
$data | string |
要解密的加密数据。 |
$passwordBased | boolean |
设置为 true 以使用基于密码的密钥派生 |
$secret | string |
解密密码或密钥 |
$info | string|null |
上下文/应用程序特定信息,@see encrypt() |
返回值 | boolean|string |
解密后的数据或身份验证失败时的 false |
---|---|---|
抛出异常 | yii\base\InvalidConfigException |
在 OpenSSL 未加载时 |
抛出异常 | yii\base\Exception |
在 OpenSSL 错误时 |
protected function decrypt($data, $passwordBased, $secret, $info)
{
if (!extension_loaded('openssl')) {
throw new InvalidConfigException('Encryption requires the OpenSSL PHP extension');
}
if (!isset($this->allowedCiphers[$this->cipher][0], $this->allowedCiphers[$this->cipher][1])) {
throw new InvalidConfigException($this->cipher . ' is not an allowed cipher');
}
list($blockSize, $keySize) = $this->allowedCiphers[$this->cipher];
$keySalt = StringHelper::byteSubstr($data, 0, $keySize);
if ($passwordBased) {
$key = $this->pbkdf2($this->kdfHash, $secret, $keySalt, $this->derivationIterations, $keySize);
} else {
$key = $this->hkdf($this->kdfHash, $secret, $keySalt, $info, $keySize);
}
$authKey = $this->hkdf($this->kdfHash, $key, null, $this->authKeyInfo, $keySize);
$data = $this->validateData(StringHelper::byteSubstr($data, $keySize, null), $authKey);
if ($data === false) {
return false;
}
$iv = StringHelper::byteSubstr($data, 0, $blockSize);
$encrypted = StringHelper::byteSubstr($data, $blockSize, null);
$decrypted = openssl_decrypt($encrypted, $this->cipher, $key, OPENSSL_RAW_DATA, $iv);
if ($decrypted === false) {
throw new \yii\base\Exception('OpenSSL failure on decryption: ' . openssl_error_string());
}
return $decrypted;
}
验证并解密使用 encryptByKey() 加密的 data。
另见 encryptByKey()。
public boolean|string decryptByKey ( $data, $inputKey, $info = null ) | ||
$data | string |
要解密的加密数据 |
$inputKey | string |
用于加密和身份验证的输入 |
$info | string|null |
可选的上下文和应用程序特定信息,请参见 hkdf() |
返回值 | boolean|string |
解密后的数据或身份验证失败时的 false |
---|
public function decryptByKey($data, $inputKey, $info = null)
{
return $this->decrypt($data, false, $inputKey, $info);
}
验证并解密使用 encryptByPassword() 加密的 data。
public boolean|string decryptByPassword ( $data, $password ) | ||
$data | string |
要解密的加密数据 |
$password | string |
用于解密的密码 |
返回值 | boolean|string |
解密后的数据或身份验证失败时的 false |
---|
public function decryptByPassword($data, $password)
{
return $this->decrypt($data, true, $password, null);
}
public yii\base\Behavior|null detachBehavior ( $name ) | ||
$name | string |
行为的名称。 |
返回值 | yii\base\Behavior|null |
分离的行为。如果行为不存在,则为 Null。 |
---|
public function detachBehavior($name)
{
$this->ensureBehaviors();
if (isset($this->_behaviors[$name])) {
$behavior = $this->_behaviors[$name];
unset($this->_behaviors[$name]);
$behavior->detach();
return $behavior;
}
return null;
}
定义在: yii\base\Component::detachBehaviors()
从组件中分离所有行为。
public void detachBehaviors ( ) |
public function detachBehaviors()
{
$this->ensureBehaviors();
foreach ($this->_behaviors as $name => $behavior) {
$this->detachBehavior($name);
}
}
加密 data。
另见 decrypt()。
protected string encrypt ( $data, $passwordBased, $secret, $info ) | ||
$data | string |
要加密的数据 |
$passwordBased | boolean |
设置为 true 以使用基于密码的密钥派生 |
$secret | string |
加密密码或密钥 |
$info | string|null |
上下文/应用程序特定信息,例如用户 ID 请参见 RFC 5869 第 3.2 节 以获取更多详细信息。 |
返回值 | string |
加密后的数据作为字节字符串 |
---|---|---|
抛出异常 | yii\base\InvalidConfigException |
在 OpenSSL 未加载时 |
抛出异常 | yii\base\Exception |
在 OpenSSL 错误时 |
protected function encrypt($data, $passwordBased, $secret, $info)
{
if (!extension_loaded('openssl')) {
throw new InvalidConfigException('Encryption requires the OpenSSL PHP extension');
}
if (!isset($this->allowedCiphers[$this->cipher][0], $this->allowedCiphers[$this->cipher][1])) {
throw new InvalidConfigException($this->cipher . ' is not an allowed cipher');
}
list($blockSize, $keySize) = $this->allowedCiphers[$this->cipher];
$keySalt = $this->generateRandomKey($keySize);
if ($passwordBased) {
$key = $this->pbkdf2($this->kdfHash, $secret, $keySalt, $this->derivationIterations, $keySize);
} else {
$key = $this->hkdf($this->kdfHash, $secret, $keySalt, $info, $keySize);
}
$iv = $this->generateRandomKey($blockSize);
$encrypted = openssl_encrypt($data, $this->cipher, $key, OPENSSL_RAW_DATA, $iv);
if ($encrypted === false) {
throw new \yii\base\Exception('OpenSSL failure on encryption: ' . openssl_error_string());
}
$authKey = $this->hkdf($this->kdfHash, $key, null, $this->authKeyInfo, $keySize);
$hashed = $this->hashData($iv . $encrypted, $authKey);
/*
* Output: [keySalt][MAC][IV][ciphertext]
* - keySalt is KEY_SIZE bytes long
* - MAC: message authentication code, length same as the output of MAC_HASH
* - IV: initialization vector, length $blockSize
*/
return $keySalt . $hashed;
}
使用加密密钥加密 data。
使用 HKDF 和随机盐从输入密钥派生用于加密和身份验证的密钥,与 encryptByPassword() 相比,速度非常快。输入密钥必须是正确随机的 - 使用 generateRandomKey() 生成密钥。加密数据包含密钥消息认证码 (MAC),因此无需对输入或输出数据进行哈希处理。
另见
public string encryptByKey ( $data, $inputKey, $info = null ) | ||
$data | string |
要加密的数据 |
$inputKey | string |
用于加密和身份验证的输入 |
$info | string|null |
可选的上下文和应用程序特定信息,请参见 hkdf() |
返回值 | string |
加密后的数据作为字节字符串 |
---|
public function encryptByKey($data, $inputKey, $info = null)
{
return $this->encrypt($data, false, $inputKey, $info);
}
使用密码加密 data。
使用 PBKDF2 和随机盐从密码中派生用于加密和身份验证的密钥,这故意很慢以防止字典攻击。使用 encryptByKey() 使用加密密钥而不是密码快速加密。密钥派生时间由 $derivationIterations 决定,它应该尽可能地设置得高。加密数据包含密钥消息认证码 (MAC),因此无需对输入或输出数据进行哈希处理。 > 注意:尽可能避免使用密码进行加密。任何东西都无法防御质量差或被泄露的密码。
另见
public string encryptByPassword ( $data, $password ) | ||
$data | string |
要加密的数据 |
$password | string |
用于加密的密码 |
返回值 | string |
加密后的数据作为字节字符串 |
---|
public function encryptByPassword($data, $password)
{
return $this->encrypt($data, true, $password, null);
}
定义在: yii\base\Component::ensureBehaviors()
确保 behaviors() 中声明的行为已附加到此组件。
public void ensureBehaviors ( ) |
public function ensureBehaviors()
{
if ($this->_behaviors === null) {
$this->_behaviors = [];
foreach ($this->behaviors() as $name => $behavior) {
$this->attachBehaviorInternal($name, $behavior);
}
}
}
从密码和随机盐生成安全哈希。
生成的哈希可以存储在数据库中。稍后当需要验证密码时,可以获取哈希并将其传递给 validatePassword()。例如,
// generates the hash (usually done during user registration or when the password is changed)
$hash = Yii::$app->getSecurity()->generatePasswordHash($password);
// ...save $hash in database...
// during login, validate if the password entered is correct using $hash fetched from database
if (Yii::$app->getSecurity()->validatePassword($password, $hash)) {
// password is good
} else {
// password is bad
}
public string generatePasswordHash ( $password, $cost = null ) | ||
$password | string |
要哈希的密码。 |
$cost | integer|null |
Blowfish 哈希算法使用的成本参数。成本值越高,生成哈希和验证密码所花费的时间就越长。因此,成本越高会减缓暴力攻击。为了最大程度地防止暴力攻击,将其设置为生产服务器上可容忍的最高值。计算哈希所需的时间每增加 $cost 一次就会翻倍。 |
返回值 | string |
密码哈希字符串。当 $passwordHashStrategy 设置为 'crypt' 时,输出始终为 60 个 ASCII 字符,当设置为 'password_hash' 时,输出长度可能会在 PHP 的未来版本中增加 (https://php.ac.cn/manual/en/function.password-hash.php) |
---|---|---|
抛出异常 | yii\base\Exception |
在密码参数或成本参数错误时。 |
public function generatePasswordHash($password, $cost = null)
{
if ($cost === null) {
$cost = $this->passwordHashCost;
}
if (function_exists('password_hash')) {
/* @noinspection PhpUndefinedConstantInspection */
return password_hash($password, PASSWORD_DEFAULT, ['cost' => $cost]);
}
$salt = $this->generateSalt($cost);
$hash = crypt($password, $salt);
// strlen() is safe since crypt() returns only ascii
if (!is_string($hash) || strlen($hash) !== 60) {
throw new Exception('Unknown error occurred while generating hash.');
}
return $hash;
}
public string generateRandomKey ( $length = 32 ) | ||
$length | integer |
要生成的字节数 |
返回值 | string |
生成的随机字节 |
---|---|---|
抛出异常 | yii\base\InvalidArgumentException |
如果指定了错误的长度 |
抛出异常 | yii\base\Exception |
失败时。 |
public function generateRandomKey($length = 32)
{
if (!is_int($length)) {
throw new InvalidArgumentException('First parameter ($length) must be an integer');
}
if ($length < 1) {
throw new InvalidArgumentException('First parameter ($length) must be greater than 0');
}
return random_bytes($length);
}
生成指定长度的随机字符串。
生成的字符串与 [A-Za-z0-9_-]+ 匹配,并且对 URL 编码透明。
public string generateRandomString ( $length = 32 ) | ||
$length | integer |
密钥的字符长度 |
返回值 | string |
生成的随机密钥 |
---|---|---|
抛出异常 | yii\base\Exception |
失败时。 |
public function generateRandomString($length = 32)
{
if (!is_int($length)) {
throw new InvalidArgumentException('First parameter ($length) must be an integer');
}
if ($length < 1) {
throw new InvalidArgumentException('First parameter ($length) must be greater than 0');
}
$bytes = $this->generateRandomKey($length);
return substr(StringHelper::base64UrlEncode($bytes), 0, $length);
}
生成可用于生成密码哈希的盐。
PHP 的 crypt() 内置函数要求 Blowfish 哈希算法的盐字符串采用特定格式:"$2a$"、"$2x$" 或 "$2y$",一个两位数的成本参数,"$" 以及来自字母表 "./0-9A-Za-z" 的 22 个字符。
protected string generateSalt ( $cost = 13 ) | ||
$cost | integer |
成本参数 |
返回值 | string |
随机盐值。 |
---|---|---|
抛出异常 | yii\base\InvalidArgumentException |
如果成本参数超出 4 到 31 的范围。 |
protected function generateSalt($cost = 13)
{
$cost = (int) $cost;
if ($cost < 4 || $cost > 31) {
throw new InvalidArgumentException('Cost must be between 4 and 31.');
}
// Get a 20-byte random string
$rand = $this->generateRandomKey(20);
// Form the prefix that specifies Blowfish (bcrypt) algorithm and cost parameter.
$salt = sprintf('$2y$%02d$', $cost);
// Append the random salt data in the required base64 format.
$salt .= str_replace('+', '.', substr(base64_encode($rand), 0, 22));
return $salt;
}
定义于: yii\base\Component::getBehavior()
返回命名的行为对象。
public yii\base\Behavior|null getBehavior ( $name ) | ||
$name | string |
行为名称 |
返回值 | yii\base\Behavior|null |
行为对象,如果行为不存在则为 null |
---|
public function getBehavior($name)
{
$this->ensureBehaviors();
return isset($this->_behaviors[$name]) ? $this->_behaviors[$name] : null;
}
定义于: yii\base\Component::getBehaviors()
返回附加到此组件的所有行为。
public yii\base\Behavior[] getBehaviors ( ) | ||
返回值 | yii\base\Behavior[] |
附加到此组件的行为列表 |
---|
public function getBehaviors()
{
$this->ensureBehaviors();
return $this->_behaviors;
}
定义于: yii\base\Component::hasEventHandlers()
返回一个值,指示是否有任何处理程序附加到命名的事件。
public boolean hasEventHandlers ( $name ) | ||
$name | string |
事件名称 |
返回值 | boolean |
是否存在任何附加到事件的处理程序。 |
---|
public function hasEventHandlers($name)
{
$this->ensureBehaviors();
if (!empty($this->_events[$name])) {
return true;
}
foreach ($this->_eventWildcards as $wildcard => $handlers) {
if (!empty($handlers) && StringHelper::matchWildcard($wildcard, $name)) {
return true;
}
}
return Event::hasHandlers($this, $name);
}
定义于: yii\base\Component::hasMethod()
返回一个值,指示是否定义了方法。
如果定义了一个方法
- 该类具有一个具有指定名称的方法
- 附加的行为具有一个具有给定名称的方法(当
$checkBehaviors
为 true 时)。
public boolean hasMethod ( $name, $checkBehaviors = true ) | ||
$name | string |
属性名称 |
$checkBehaviors | boolean |
是否将行为的方法视为此组件的方法 |
返回值 | boolean |
方法是否已定义 |
---|
public function hasMethod($name, $checkBehaviors = true)
{
if (method_exists($this, $name)) {
return true;
} elseif ($checkBehaviors) {
$this->ensureBehaviors();
foreach ($this->_behaviors as $behavior) {
if ($behavior->hasMethod($name)) {
return true;
}
}
}
return false;
}
定义于: yii\base\Component::hasProperty()
返回一个值,指示是否为该组件定义了属性。
如果定义了一个属性
- 该类具有与指定名称关联的 getter 或 setter 方法(在这种情况下,属性名称不区分大小写);
- 该类具有与指定名称相同的成员变量(当
$checkVars
为真时); - 附加的行为具有给定名称的属性(当
$checkBehaviors
为 true 时)。
另见
public boolean hasProperty ( $name, $checkVars = true, $checkBehaviors = true ) | ||
$name | string |
属性名称 |
$checkVars | boolean |
是否将成员变量视为属性 |
$checkBehaviors | boolean |
是否将行为的属性视为此组件的属性 |
返回值 | boolean |
属性是否已定义 |
---|
public function hasProperty($name, $checkVars = true, $checkBehaviors = true)
{
return $this->canGetProperty($name, $checkVars, $checkBehaviors) || $this->canSetProperty($name, false, $checkBehaviors);
}
使用键控哈希值作为前缀附加到 data,以便以后可以检测到 data 是否被篡改。
不需要对 encryptByKey() 或 encryptByPassword() 的输入或输出进行哈希处理,因为这些方法执行此任务。
另见
public string hashData ( $data, $key, $rawHash = false ) | ||
$data | string |
要保护的数据 |
$key | string |
用于生成哈希的密钥。应为安全的加密密钥。 |
$rawHash | boolean |
生成的哈希值是否为原始二进制格式。如果为 false,则将生成小写十六进制数字。 |
返回值 | string |
带密钥哈希前缀的数据 |
---|---|---|
抛出异常 | yii\base\InvalidConfigException |
当 HMAC 生成失败时。 |
public function hashData($data, $key, $rawHash = false)
{
$hash = hash_hmac($this->macHash, $data, $key, $rawHash);
if (!$hash) {
throw new InvalidConfigException('Failed to generate HMAC with hash algorithm: ' . $this->macHash);
}
return $hash . $data;
}
使用标准 HKDF 算法从给定的输入密钥推导出密钥。
实现 RFC 5869 中指定的 HKDF。建议使用以下 SHA-2 哈希算法之一:sha224、sha256、sha384 或 sha512。
public string hkdf ( $algo, $inputKey, $salt = null, $info = null, $length = 0 ) | ||
$algo | string |
|
$inputKey | string |
源密钥 |
$salt | string|null |
随机盐 |
$info | string|null |
可选信息,用于将派生密钥材料绑定到特定于应用程序和上下文的的信息,例如用户 ID 或 API 版本,请参阅 RFC 5869 |
$length | integer |
输出密钥的字节长度。如果为 0,则输出密钥为哈希算法输出的长度。 |
返回值 | string |
派生密钥 |
---|---|---|
抛出异常 | yii\base\InvalidArgumentException |
当 HMAC 生成失败时。 |
public function hkdf($algo, $inputKey, $salt = null, $info = null, $length = 0)
{
if (function_exists('hash_hkdf')) {
$outputKey = hash_hkdf((string)$algo, (string)$inputKey, $length, (string)$info, (string)$salt);
if ($outputKey === false) {
throw new InvalidArgumentException('Invalid parameters to hash_hkdf()');
}
return $outputKey;
}
$test = @hash_hmac($algo, '', '', true);
if (!$test) {
throw new InvalidArgumentException('Failed to generate HMAC with hash algorithm: ' . $algo);
}
$hashLength = StringHelper::byteLength($test);
if (is_string($length) && preg_match('{^\d{1,16}$}', $length)) {
$length = (int) $length;
}
if (!is_int($length) || $length < 0 || $length > 255 * $hashLength) {
throw new InvalidArgumentException('Invalid length');
}
$blocks = $length !== 0 ? ceil($length / $hashLength) : 1;
if ($salt === null) {
$salt = str_repeat("\0", $hashLength);
}
$prKey = hash_hmac($algo, $inputKey, $salt, true);
$hmac = '';
$outputKey = '';
for ($i = 1; $i <= $blocks; $i++) {
$hmac = hash_hmac($algo, $hmac . $info . chr($i), $prKey, true);
$outputKey .= $hmac;
}
if ($length !== 0) {
$outputKey = StringHelper::byteSubstr($outputKey, 0, $length);
}
return $outputKey;
}
public void init ( ) |
public function init()
{
}
屏蔽令牌,使其不可压缩。
对令牌应用随机掩码,并将使用的掩码追加到结果中,使字符串始终唯一。用于通过随机化令牌在每个请求上的输出方式来缓解 BREACH 攻击。
public string maskToken ( $token ) | ||
$token | string |
未掩码的令牌。 |
返回值 | string |
已掩码的令牌。 |
---|
public function maskToken($token)
{
// The number of bytes in a mask is always equal to the number of bytes in a token.
$mask = $this->generateRandomKey(StringHelper::byteLength($token));
return StringHelper::base64UrlEncode($mask . ($mask ^ $token));
}
定义于: yii\base\Component::off()
从该组件中分离现有的事件处理程序。
此方法与 on() 相反。
注意:如果为事件名称传递通配符模式,则仅使用此通配符注册的处理程序将被删除,而使用与该通配符匹配的普通名称注册的处理程序将保留。
另请参阅 on()。
public boolean off ( $name, $handler = null ) | ||
$name | string |
事件名称 |
$handler | callable|null |
要删除的事件处理程序。如果为 null,则将删除附加到指定事件的所有处理程序。 |
返回值 | boolean |
如果找到并分离了处理程序 |
---|
public function off($name, $handler = null)
{
$this->ensureBehaviors();
if (empty($this->_events[$name]) && empty($this->_eventWildcards[$name])) {
return false;
}
if ($handler === null) {
unset($this->_events[$name], $this->_eventWildcards[$name]);
return true;
}
$removed = false;
// plain event names
if (isset($this->_events[$name])) {
foreach ($this->_events[$name] as $i => $event) {
if ($event[0] === $handler) {
unset($this->_events[$name][$i]);
$removed = true;
}
}
if ($removed) {
$this->_events[$name] = array_values($this->_events[$name]);
return true;
}
}
// wildcard event names
if (isset($this->_eventWildcards[$name])) {
foreach ($this->_eventWildcards[$name] as $i => $event) {
if ($event[0] === $handler) {
unset($this->_eventWildcards[$name][$i]);
$removed = true;
}
}
if ($removed) {
$this->_eventWildcards[$name] = array_values($this->_eventWildcards[$name]);
// remove empty wildcards to save future redundant regex checks:
if (empty($this->_eventWildcards[$name])) {
unset($this->_eventWildcards[$name]);
}
}
}
return $removed;
}
将事件处理程序附加到事件。
事件处理程序必须是有效的 PHP 回调函数。以下是一些示例
function ($event) { ... } // anonymous function
[$object, 'handleClick'] // $object->handleClick()
['Page', 'handleClick'] // Page::handleClick()
'handleClick' // global function handleClick()
事件处理程序必须使用以下签名定义,
function ($event)
其中 $event
是一个 yii\base\Event 对象,其中包含与事件关联的参数。
从 2.0.14 版本开始,您可以将事件名称指定为通配符模式
$component->on('event.group.*', function ($event) {
Yii::trace($event->name . ' is triggered.');
});
另请参阅 off()。
public void on ( $name, $handler, $data = null, $append = true ) | ||
$name | string |
事件名称 |
$handler | callable |
事件处理程序 |
$data | mixed |
要传递给事件处理程序的数据,当事件触发时。当调用事件处理程序时,可以通过 yii\base\Event::$data 访问这些数据。 |
$append | boolean |
是否将新的事件处理程序附加到现有处理程序列表的末尾。如果为 false,则新处理程序将插入到现有处理程序列表的开头。 |
public function on($name, $handler, $data = null, $append = true)
{
$this->ensureBehaviors();
if (strpos($name, '*') !== false) {
if ($append || empty($this->_eventWildcards[$name])) {
$this->_eventWildcards[$name][] = [$handler, $data];
} else {
array_unshift($this->_eventWildcards[$name], [$handler, $data]);
}
return;
}
if ($append || empty($this->_events[$name])) {
$this->_events[$name][] = [$handler, $data];
} else {
array_unshift($this->_events[$name], [$handler, $data]);
}
}
使用标准 PBKDF2 算法从给定的密码推导出密钥。
实施了 RFC 2898 中指定的 HKDF2 建议使用 SHA-2 散列算法之一:sha224、sha256、sha384 或 sha512。
public string pbkdf2 ( $algo, $password, $salt, $iterations, $length = 0 ) | ||
$algo | string |
|
$password | string |
源密码 |
$salt | string |
随机盐 |
$iterations | integer |
散列算法的迭代次数。设置尽可能高的值以阻碍字典密码攻击。 |
$length | integer |
输出密钥的字节长度。如果为 0,则输出密钥为哈希算法输出的长度。 |
返回值 | string |
派生密钥 |
---|---|---|
抛出异常 | yii\base\InvalidArgumentException |
当散列生成由于给定的参数无效而失败时。 |
public function pbkdf2($algo, $password, $salt, $iterations, $length = 0)
{
if (function_exists('hash_pbkdf2') && PHP_VERSION_ID >= 50500) {
$outputKey = hash_pbkdf2($algo, $password, $salt, $iterations, $length, true);
if ($outputKey === false) {
throw new InvalidArgumentException('Invalid parameters to hash_pbkdf2()');
}
return $outputKey;
}
// todo: is there a nice way to reduce the code repetition in hkdf() and pbkdf2()?
$test = @hash_hmac($algo, '', '', true);
if (!$test) {
throw new InvalidArgumentException('Failed to generate HMAC with hash algorithm: ' . $algo);
}
if (is_string($iterations) && preg_match('{^\d{1,16}$}', $iterations)) {
$iterations = (int) $iterations;
}
if (!is_int($iterations) || $iterations < 1) {
throw new InvalidArgumentException('Invalid iterations');
}
if (is_string($length) && preg_match('{^\d{1,16}$}', $length)) {
$length = (int) $length;
}
if (!is_int($length) || $length < 0) {
throw new InvalidArgumentException('Invalid length');
}
$hashLength = StringHelper::byteLength($test);
$blocks = $length !== 0 ? ceil($length / $hashLength) : 1;
$outputKey = '';
for ($j = 1; $j <= $blocks; $j++) {
$hmac = hash_hmac($algo, $salt . pack('N', $j), $password, true);
$xorsum = $hmac;
for ($i = 1; $i < $iterations; $i++) {
$hmac = hash_hmac($algo, $hmac, $password, true);
$xorsum ^= $hmac;
}
$outputKey .= $xorsum;
}
if ($length !== 0) {
$outputKey = StringHelper::byteSubstr($outputKey, 0, $length);
}
return $outputKey;
}
protected boolean shouldUseLibreSSL ( ) | ||
返回值 | boolean |
如果应该使用 LibreSSL 使用的版本为 2.1.5 或更高版本。 |
---|
protected function shouldUseLibreSSL()
{
if ($this->_useLibreSSL === null) {
// Parse OPENSSL_VERSION_TEXT because OPENSSL_VERSION_NUMBER is no use for LibreSSL.
// https://bugs.php.net/bug.php?id=71143
$this->_useLibreSSL = defined('OPENSSL_VERSION_TEXT')
&& preg_match('{^LibreSSL (\d\d?)\.(\d\d?)\.(\d\d?)$}', OPENSSL_VERSION_TEXT, $matches)
&& (10000 * $matches[1]) + (100 * $matches[2]) + $matches[3] >= 20105;
}
return $this->_useLibreSSL;
}
public void trigger ( $name, yii\base\Event $event = null ) | ||
$name | string |
事件名称 |
$event | yii\base\Event|null |
事件实例。如果未设置,将创建一个默认的 yii\base\Event 对象。 |
public function trigger($name, Event $event = null)
{
$this->ensureBehaviors();
$eventHandlers = [];
foreach ($this->_eventWildcards as $wildcard => $handlers) {
if (StringHelper::matchWildcard($wildcard, $name)) {
$eventHandlers[] = $handlers;
}
}
if (!empty($this->_events[$name])) {
$eventHandlers[] = $this->_events[$name];
}
if (!empty($eventHandlers)) {
$eventHandlers = call_user_func_array('array_merge', $eventHandlers);
if ($event === null) {
$event = new Event();
}
if ($event->sender === null) {
$event->sender = $this;
}
$event->handled = false;
$event->name = $name;
foreach ($eventHandlers as $handler) {
$event->data = $handler[1];
call_user_func($handler[0], $event);
// stop further handling if the event is handled
if ($event->handled) {
return;
}
}
}
// invoke class-level attached handlers
Event::trigger($this, $name, $event);
}
取消屏蔽先前由 maskToken
屏蔽的令牌。
public string unmaskToken ( $maskedToken ) | ||
$maskedToken | string |
已掩码的令牌。 |
返回值 | string |
未掩码的令牌,如果令牌格式无效,则为空字符串。 |
---|
public function unmaskToken($maskedToken)
{
$decoded = StringHelper::base64UrlDecode($maskedToken);
$length = StringHelper::byteLength($decoded) / 2;
// Check if the masked token has an even length.
if (!is_int($length)) {
return '';
}
return StringHelper::byteSubstr($decoded, $length, $length) ^ StringHelper::byteSubstr($decoded, 0, $length);
}
验证给定的 data 是否被篡改。
另请参阅 hashData()。
public string|false validateData ( $data, $key, $rawHash = false ) | ||
$data | string |
要验证的数据。数据必须是之前由 hashData() 生成的。 |
$key | string |
之前用于为 hashData() 中的数据生成散列的密钥。函数查看系统上支持的散列算法。这必须与生成数据的散列时传递给 hashData() 的值相同。 |
$rawHash | boolean |
这应该与使用 hashData() 生成数据时的值相同。它指示数据中的散列值是否为二进制格式。如果为 false,则表示散列值仅包含小写十六进制数字。十六进制数字将被生成。 |
返回值 | string|false |
带有剥离散列的真实数据。如果数据被篡改,则为 false。 |
---|---|---|
抛出异常 | yii\base\InvalidConfigException |
当 HMAC 生成失败时。 |
public function validateData($data, $key, $rawHash = false)
{
$test = @hash_hmac($this->macHash, '', '', $rawHash);
if (!$test) {
throw new InvalidConfigException('Failed to generate HMAC with hash algorithm: ' . $this->macHash);
}
$hashLength = StringHelper::byteLength($test);
if (StringHelper::byteLength($data) >= $hashLength) {
$hash = StringHelper::byteSubstr($data, 0, $hashLength);
$pureData = StringHelper::byteSubstr($data, $hashLength, null);
$calculatedHash = hash_hmac($this->macHash, $pureData, $key, $rawHash);
if ($this->compareString($hash, $calculatedHash)) {
return $pureData;
}
}
return false;
}
验证密码是否与哈希值匹配。
另请参阅 generatePasswordHash().
public boolean validatePassword ( $password, $hash ) | ||
$password | string |
要验证的密码。 |
$hash | string |
要验证密码的散列。 |
返回值 | boolean |
密码是否正确。 |
---|---|---|
抛出异常 | yii\base\InvalidArgumentException |
在密码/散列参数错误或 crypt() 无法使用 Blowfish 散列的情况下。 |
public function validatePassword($password, $hash)
{
if (!is_string($password) || $password === '') {
throw new InvalidArgumentException('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
) {
throw new InvalidArgumentException('Hash is invalid.');
}
if (function_exists('password_verify')) {
return password_verify($password, $hash);
}
$test = crypt($password, $hash);
$n = strlen($test);
if ($n !== 60) {
return false;
}
return $this->compareString($test, $hash);
}
注册 或 登录 以发表评论。