yii2的用戶登錄hash及其驗證分析

使用gii生成用戶表的model生成的幾個方法解析:

隨機數生成

 protected function generateSalt($cost = 13)
    {
        $cost = (int) $cost;
        if ($cost < 4 || $cost > 31) {
            throw new InvalidParamException('Cost must be between 4 and 31.');
        }

        $rand = $this->generateRandomKey(20);
        $salt = sprintf("$2y$%02d$", $cost);
        $salt .= str_replace('+', '.', substr(base64_encode($rand), 0, 22));

        return $salt;
    }

(1)、生成隨機數:$rand = $this->generateRandomKey(20);

(2)、加上前綴:$salt = sprintf("$2y$%02d$", $cost);   $cost=13時默認前綴爲$2y$13$

(3)、將$rand用base64加密,取前22位,並將+替換爲.,最後加上前綴返回

原理,使用blowfish標準加密生成60個字符的hash,利用salt的最大長度(個人理解,salt最大長度應該是在21到22個字符之間),將hash作爲salt與明文密碼加密可得出一樣的結果;密碼最大爲74個字符,超出則與74個字符密文相同;


setPassword()方法:

2、validatePassword($password)的方法

該方法會調用yii2/base/Security的validPassword()方法,

Security中的validPassword()方法會將用戶輸入的密碼與數據庫中的hash值一起加密

$test = crypt($password, $hash);
                $n = strlen($test);
                if ($n !== 60) {
                    return false;
                }
                return $this->compareString($test, $hash);

然後返回compareString($test, $hash)方法的結果

compareString方法:

      

        //加上結束標記,防止mb_strlen()函數找不到結束標記

        $expected .= "\0";
        $actual .= "\0";

        //調用mb_strlen($string, '8bit')函數按位獲取字符串長度

        $expectedLength = StringHelper::byteLength($expected);
        $actualLength = StringHelper::byteLength($actual);

        //獲得長度差值
        $diff = $expectedLength - $actualLength;
        //循環對比每一位的ascii值是否相等(先將密文hash與用戶輸入加密後的字符串按位與,然後與diff按位或,返回結果)
        for ($i = 0; $i < $actualLength; $i++) {
            $diff |= (ord($actual[$i]) ^ ord($expected[$i % $expectedLength]));
        }
        return $diff === 0;


用到的相關函數:

ord():

回字符串第一個字符的 ASCII 值

crypt(str,salt):

    str:必需。規定要編碼的字符串。

    salt:可選。用於增加被編碼字符數目的字符串,以使編碼更加安全。如果未提供 salt 參數,則每次調用該函數時會隨機生成一個。

mb_strlen():

獲取字符串的長度,第二個參數爲字符編碼。如果省略,則使用內部字符編碼。

PHP相關位運算符:

$a & $b     And(按位與)     將把 $a 和 $b 中都爲 1 的位設爲 1。

$a | $b     Or(按位或)     將把 $a 和 $b 中任何一個爲 1 的位設爲 1。

$a ^ $b     Xor(按位異或)     將把 $a 和 $b 中一個爲 1 另一個爲 0 的位設爲 1。

~ $a     Not(按位取反)     將 $a 中爲 0 的位設爲 1,反之亦然。

$a << $b     Shift left(左移)     將 $a 中的位向左移動 $b 次(每一次移動都表示“乘以 2”)。

$a >> $b     Shift right(右移)     將 $a 中的位向右移動 $b 次(每一次移動都表示“除以 2”)。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章