您好,登錄后才能下訂單哦!
這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)?lái)有關(guān)怎么在PHP中實(shí)現(xiàn)一個(gè)密碼散列算法,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
首先,我們還是看看當(dāng)前環(huán)境中所支持的 password_hash() 算法。
print_r(password_algos()); // Array // ( // [0] => 2y // )
可以看出,當(dāng)前環(huán)境中,我們只有 2y 這一種算法可以使用,這個(gè)函數(shù)是 PHP7.4 才提供的。我們簡(jiǎn)單的了解一下即可。
重點(diǎn)還是在這個(gè)加密函數(shù)的應(yīng)用上,我們就來(lái)看看 password_hash() 這個(gè)函數(shù)的使用。這個(gè)函數(shù)是在 PHP5.5 之后就已經(jīng)提供了,大家可以放心地使用。
echo password_hash("this is password", PASSWORD_DEFAULT), PHP_EOL; // $2y$10$vOI56sADJPhebhzq5Bj1quM7grMex3Y4NlI99C3qP83iveEGnfdd. echo password_hash("this is password", PASSWORD_DEFAULT), PHP_EOL; // $2y$10$YMq8zsTw32HCOeWmlLSpruWKiSoO/rlNu2OVcIV4hlVSY4enn8GwS
沒(méi)錯(cuò),就是這么地簡(jiǎn)單,PASSWORD_DEFAULT 是我們指定的加密算法,這里我們給的就是一個(gè)默認(rèn)值。然而加密出來(lái)的數(shù)據(jù)并不是像 md5() 之類的是一個(gè) 16進(jìn)制 字符串呀。是的,password_hash() 加密出來(lái)的內(nèi)容并不是 md5 類型的 Hash 串,而是類似于像 JWT 一樣的一套加密字符串。
關(guān)于 JWT 的內(nèi)容大家可以自行了解一下,在這里,最主要的就是 password_hash() 加密出來(lái)的內(nèi)容和 JWT 一樣,在加密串的里面是包含一些信息的,比如加密循環(huán)次數(shù)和鹽值信息。這些信息是后面我們進(jìn)行密碼匹配時(shí)所必須的內(nèi)容。
有人又說(shuō)了,既然有鹽值,為什么我們沒(méi)有定義這個(gè)鹽值呀,這樣我們后面如何匹配呢?就像前面說(shuō)的那樣,這個(gè)加密后的字符串本身已經(jīng)包含了鹽值信息,而且這個(gè)鹽值信息是系統(tǒng)隨機(jī)生成的,只能使用對(duì)應(yīng)的比較函數(shù)才能比較原始明文密碼和加密后的密碼是否一致,這樣就能讓系統(tǒng)的安全性提高很多。
請(qǐng)注意上面的測(cè)試代碼,我們兩段代碼的明文是一樣的,但是加密出來(lái)的密碼散列可是完全不相同的哦。當(dāng)然,更重要的是,這個(gè)加密后的密碼也是不可反解碼的,是一個(gè)正規(guī)的單向 Hash 散列。所以它是非常安全的一個(gè)密碼加密函數(shù),這也是官方推薦它的原因。
那么,我們可以指定它的鹽值嗎?當(dāng)然可以。
$options = [ 'cost' => 12, ]; echo password_hash("rasmuslerdorf", PASSWORD_BCRYPT, $options), PHP_EOL; // $2y$12$YjEdiCJHAmPCoidNvgrZq.k4VH3ShoELWlyU9POHD5sV3L1WW4.vS $options = [ 'cost' => 11, 'salt' => mcrypt_create_iv(22, MCRYPT_DEV_URANDOM), ]; echo password_hash("rasmuslerdorf", PASSWORD_BCRYPT, $options); // $2y$11$syLcOhq1Mfc32cWVi1zyLOvSn.AtcCre.kY999uUXZ6pS3nXNv1lmPHP
最后一個(gè)參數(shù)是一個(gè)選項(xiàng)數(shù)組,在這個(gè)選項(xiàng)數(shù)組中,cost 代表加密循環(huán)次數(shù)(循環(huán)加密多少次),salt 當(dāng)然就是我們的鹽值了,這里使用的是 mcrypt_create_iv() 生成的,我們也可以使用自己生成的隨機(jī)字符串來(lái)當(dāng)做 salt 使用。
不過(guò),劃重點(diǎn)了,在 PHP7 以后,選項(xiàng)參數(shù)數(shù)組中的 salt 已經(jīng)是被標(biāo)記成過(guò)時(shí)廢棄狀態(tài)了。如果使用這個(gè)的話,會(huì)報(bào)出 deprecated 警告。也就是說(shuō),官方期望我們還是不要使用自定義的 salt 來(lái)進(jìn)行加密,而是使用默認(rèn)情況下的由系統(tǒng)自動(dòng)隨機(jī)生成的 salt 。
所以,我們?cè)谌粘J褂弥校苯邮褂玫谝恍写a那種形式進(jìn)行加密就可以了,有特殊需要的話,可以指定 cost 來(lái)改變循環(huán)次數(shù),不同的循環(huán)次數(shù)要根據(jù)當(dāng)前系統(tǒng)的硬件來(lái)定,當(dāng)然越高對(duì)于系統(tǒng)來(lái)說(shuō)也需要更高的硬件支持,默認(rèn)情況下,這個(gè)值是 10 。
$p = password_hash('this is password', PASSWORD_DEFAULT, $options); print_r(password_get_info($p)); // Array // ( // [algo] => 2y // [algoName] => bcrypt // [options] => Array // ( // [cost] => 11 // ) // )
很簡(jiǎn)單的一個(gè)函數(shù),就是可以幫助我們看到這個(gè)加密數(shù)據(jù)的加密信息,就簡(jiǎn)單的說(shuō)下返回的信息內(nèi)容吧。algo 就是使用的加密算法,前面我們已經(jīng)看過(guò)當(dāng)前系統(tǒng)中只有 2y 這一種算法,所以我們使用的 PASSWORD_DEFAULT 這個(gè)默認(rèn)算法也就只能是它了。algoName 就是算法的可讀名稱,我們的算法正式名稱就是 bcrypt 算法。options 數(shù)組里面其實(shí)就是我們給定的選項(xiàng)參數(shù)內(nèi)容。從這個(gè)函數(shù)就可以看出來(lái),算法的信息真的是包含在了加密后的字符串中。
有的時(shí)候,我們想要升級(jí)當(dāng)前的密碼強(qiáng)度,比如將密碼循環(huán)次數(shù)增加,而數(shù)據(jù)庫(kù)中新老算法的密碼混雜著記錄在一起,這時(shí)應(yīng)該怎么辦呢?
var_dump(password_needs_rehash($p, PASSWORD_DEFAULT, $options)); // bool(false) var_dump(password_needs_rehash($p, PASSWORD_DEFAULT, ['cost'=>5])); // bool(true)
password_needs_rehash() 是 PHP 提供給我們的用于比對(duì)當(dāng)前加密串的內(nèi)容是否和我們所提供的算法和選項(xiàng)一致,如果是一致的返回的是 false ,如果不一致,返回的是 true 。額,這個(gè)又有點(diǎn)繞了,不是應(yīng)該一致返回的是 true 嗎?
其實(shí)從函數(shù)的名字就可以看出來(lái),這個(gè)函數(shù)的意思是 密碼(password) 是否需要(needs) 重新Hash(rehash) 。也就是說(shuō),如果算法和選項(xiàng)一致的話,那么這個(gè)密碼是不需要重新 Hash 的,當(dāng)然返回的就是 false 啦,而算法或選項(xiàng)有不一致的地方的話,這個(gè)密碼就是需要重新 Hash 的,返回的就是 true 了。大家一定不要用反了。
最后,也是最重要的,我們要驗(yàn)證明文密碼和加密密碼是否一致的時(shí)候應(yīng)該怎么辦呢?如果是原來(lái)的 md5 方式,我們將明文密碼也進(jìn)行相同的加密之后再用雙等號(hào)進(jìn)行比較就可以了。但是 password_hash() 這種就不行了,因?yàn)樗?salt 是隨機(jī)的,也不需要我們?nèi)ケ4?,所以即使是相同的字符串,我們也不能保證每次加密的結(jié)果是一樣的,那么就要使用系統(tǒng)為我們提供的驗(yàn)證函數(shù)了。
var_dump(password_verify('this is password', $p)); // bool(true) var_dump(password_verify('1this is password', $p)); // bool(false)
上述就是小編為大家分享的怎么在PHP中實(shí)現(xiàn)一個(gè)密碼散列算法了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。