站長資訊網
最全最豐富的資訊網站

詳細介紹PHP中的密碼散列算法(附代碼)

本篇文章給大家詳細介紹PHP中的密碼散列算法。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有所幫助。

詳細介紹PHP中的密碼散列算法(附代碼)

PHP密碼散列算法的學習

不知道大家有沒有看過 Laravel 的源碼。在 Laravel 源碼中,對于用戶密碼的加密,使用的是 password_hash() 這個函數。這個函數是屬于 PHP 密碼散列算法擴展中所包含的函數,它是集成在 PHP 源碼中的擴展,并且還是 PHP 官方所推薦的一種密碼加密方式。那么它有什么好處呢?

實際上,password_hash() 這一系列的函數是對 crypt() 這個加密函數的一種封裝。crypt() 函數也是一種單向散列函數,默認情況下是基于 UNIX DES 算法,這個函數的鹽值是可選參數,如果沒有鹽值的話,它會生成的是一種簡單的弱密碼,所以在 PHP5.6 之后如果 crypt() 函數沒有給鹽值的話會報警告錯誤。而 password_hash() 就是在它的基礎上增加了一套可靠的隨機鹽值生成器并封裝在這一個函數中了。具體內容我們通過下面的代碼一步一步來進行學習。

查看密碼散列函數的加密算法

首先,我們還是看看當前環境中所支持的 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 官方所推薦的函數了,那自然也是我們日后應該學習的重點內容,就連大部分的 PHP 框架中的用戶類型的密碼加密也都是使用的這套函數了。我們也就不要再使用 md5 那種加密方式了,而且數據庫還得保存我們自己的一個鹽值浪費數據庫空間,直接使用 password_hash() 方便又安全。

測試代碼:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202007/source/PHP%E5%AF%86%E7%A0%81%E6%95%A3%E5%88%97%E7%AE%97%E6%B3%95%E7%9A%84%E5%AD%A6%E4%B9%A0.php

推薦學習:php視頻教程

贊(0)
分享到: 更多 (0)
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
国产精品成人va在线观看入口| 亚洲欧洲久久精品| 一本久久A久久免费精品不卡 | 午夜精品一区二区三区在线观看| 国产精品高清久久久久久久| 亚洲国产精品美女久久久久| 精品爆乳一区二区三区无码av| 91精品啪在线观看国产线免费| 亚洲AV永久纯肉无码精品动漫| 亚洲精品无码不卡在线播HE| 久久亚洲精品无码播放| 亚洲婷婷国产精品电影人久久| 精品无码av无码专区| 日韩亚洲国产综合高清| 精品国产日韩亚洲一区| 无码国产亚洲日韩国精品视频一区二区三区 | 99视频精品全国在线观看| 久久青青草原国产精品免费| 亚洲无线观看国产精品| 国产无套精品一区二区| 99热在线日韩精品免费| 国内精品久久久久久久影视麻豆| 国产午夜精品一区二区| 成人国产精品免费视频| 日韩精品人妻一区二区中文八零| 久久亚洲av无码精品浪潮 | 亚洲色无码国产精品网站可下载 | 国产精品宾馆在线精品酒店| 国产精品无码久久综合网| 内射精品无码中文字幕| 久热爱精品视频在线| 精品熟女少妇AV免费观看| 国内精品在线播放| 精品国产成a人在线观看| 日韩精品中文字幕无码专区| 国产精品极品美女自在线| 国产av永久精品无码| 亚洲精品国产日韩| 人妻少妇精品久久| 国产精品日韩深夜福利久久| 老司机精品视频在线观看|