您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關怎么在PHP中實現一個密碼散列算法,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
首先,我們還是看看當前環境中所支持的 password_hash() 算法。
print_r(password_algos()); // Array // ( // [0] => 2y // )
可以看出,當前環境中,我們只有 2y 這一種算法可以使用,這個函數是 PHP7.4 才提供的。我們簡單的了解一下即可。
重點還是在這個加密函數的應用上,我們就來看看 password_hash() 這個函數的使用。這個函數是在 PHP5.5 之后就已經提供了,大家可以放心地使用。
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
沒錯,就是這么地簡單,PASSWORD_DEFAULT 是我們指定的加密算法,這里我們給的就是一個默認值。然而加密出來的數據并不是像 md5() 之類的是一個 16進制 字符串呀。是的,password_hash() 加密出來的內容并不是 md5 類型的 Hash 串,而是類似于像 JWT 一樣的一套加密字符串。
關于 JWT 的內容大家可以自行了解一下,在這里,最主要的就是 password_hash() 加密出來的內容和 JWT 一樣,在加密串的里面是包含一些信息的,比如加密循環次數和鹽值信息。這些信息是后面我們進行密碼匹配時所必須的內容。
有人又說了,既然有鹽值,為什么我們沒有定義這個鹽值呀,這樣我們后面如何匹配呢?就像前面說的那樣,這個加密后的字符串本身已經包含了鹽值信息,而且這個鹽值信息是系統隨機生成的,只能使用對應的比較函數才能比較原始明文密碼和加密后的密碼是否一致,這樣就能讓系統的安全性提高很多。
請注意上面的測試代碼,我們兩段代碼的明文是一樣的,但是加密出來的密碼散列可是完全不相同的哦。當然,更重要的是,這個加密后的密碼也是不可反解碼的,是一個正規的單向 Hash 散列。所以它是非常安全的一個密碼加密函數,這也是官方推薦它的原因。
那么,我們可以指定它的鹽值嗎?當然可以。
$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
最后一個參數是一個選項數組,在這個選項數組中,cost 代表加密循環次數(循環加密多少次),salt 當然就是我們的鹽值了,這里使用的是 mcrypt_create_iv() 生成的,我們也可以使用自己生成的隨機字符串來當做 salt 使用。
不過,劃重點了,在 PHP7 以后,選項參數數組中的 salt 已經是被標記成過時廢棄狀態了。如果使用這個的話,會報出 deprecated 警告。也就是說,官方期望我們還是不要使用自定義的 salt 來進行加密,而是使用默認情況下的由系統自動隨機生成的 salt 。
所以,我們在日常使用中,直接使用第一行代碼那種形式進行加密就可以了,有特殊需要的話,可以指定 cost 來改變循環次數,不同的循環次數要根據當前系統的硬件來定,當然越高對于系統來說也需要更高的硬件支持,默認情況下,這個值是 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 // ) // )
很簡單的一個函數,就是可以幫助我們看到這個加密數據的加密信息,就簡單的說下返回的信息內容吧。algo 就是使用的加密算法,前面我們已經看過當前系統中只有 2y 這一種算法,所以我們使用的 PASSWORD_DEFAULT 這個默認算法也就只能是它了。algoName 就是算法的可讀名稱,我們的算法正式名稱就是 bcrypt 算法。options 數組里面其實就是我們給定的選項參數內容。從這個函數就可以看出來,算法的信息真的是包含在了加密后的字符串中。
有的時候,我們想要升級當前的密碼強度,比如將密碼循環次數增加,而數據庫中新老算法的密碼混雜著記錄在一起,這時應該怎么辦呢?
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 提供給我們的用于比對當前加密串的內容是否和我們所提供的算法和選項一致,如果是一致的返回的是 false ,如果不一致,返回的是 true 。額,這個又有點繞了,不是應該一致返回的是 true 嗎?
其實從函數的名字就可以看出來,這個函數的意思是 密碼(password) 是否需要(needs) 重新Hash(rehash) 。也就是說,如果算法和選項一致的話,那么這個密碼是不需要重新 Hash 的,當然返回的就是 false 啦,而算法或選項有不一致的地方的話,這個密碼就是需要重新 Hash 的,返回的就是 true 了。大家一定不要用反了。
最后,也是最重要的,我們要驗證明文密碼和加密密碼是否一致的時候應該怎么辦呢?如果是原來的 md5 方式,我們將明文密碼也進行相同的加密之后再用雙等號進行比較就可以了。但是 password_hash() 這種就不行了,因為它的 salt 是隨機的,也不需要我們去保存,所以即使是相同的字符串,我們也不能保證每次加密的結果是一樣的,那么就要使用系統為我們提供的驗證函數了。
var_dump(password_verify('this is password', $p)); // bool(true) var_dump(password_verify('1this is password', $p)); // bool(false)
上述就是小編為大家分享的怎么在PHP中實現一個密碼散列算法了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。