PHP開發者如何做好密碼保護以及Laravel底層密碼儲存和驗證實現

2020-07-16 10:05:55
隨著線上攻擊的增多,密碼安全越來越重要。作為開發者我們要擔負起安全管理、計算雜湊和儲存使用者密碼的責任,不管應用是簡單的遊戲還是絕密商業檔案的倉庫,都要做到這一點。PHP內建了一些工具,讓保護密碼變得更加容易,本節我們就來討論如何根據現代的安全措施來使用這些工具。

1、密碼保護三原則

絕對不能知道使用者的密碼

我們絕對不能知道使用者的密碼,也不能有獲取使用者密碼的方式,如果應用的資料庫被黑,你肯定不希望資料庫中有純文字或能解密的密碼。任何時候,知道的越少越安全。

絕對不要約束使用者的密碼

如果要求密碼符合特定的模式,其實是為不懷好意的人提供了攻擊應用的途徑,如果必須約束密碼,我建議只限制最小長度,把常用的密碼或基於字典建立的密碼加入黑名單也是好主意。

絕對不能通過電子郵件傳送使用者密碼

如果你通過電子郵件給使用者傳送密碼,使用者會知道三件事:你知道他的密碼,你使用純文字或能解密的方式儲存了他的密碼,你沒有對通過網際網路傳送純文字的密碼感到不安。

我們應該在電子郵件中傳送用於設定或修改密碼的URL,Web應用通常會生成一個唯一的令牌,這個令牌只在設定或修改密碼時使用一次(比如修改密碼),通常我們把這個令牌作為設定或修改密碼URL的一個引數,當使用者存取這個URL時,應用會驗證令牌是否有效,如果有效則繼續操作,操作完成後,令牌失效,不能重複使用。

2、密碼儲存演算法

關於密碼儲存的最佳實踐是計算密碼的雜湊值,而不是加密使用者的密碼。加密和雜湊不是一回事,加密事雙向演算法,加密的資料可以解密,而雜湊是單向演算法,雜湊後的資料不能再還原成原始值,而且相同的資料得到的雜湊值始終相同。

在資料庫中儲存使用者的密碼,要先計算密碼的雜湊值,然後在資料庫中儲存密碼的雜湊值,如果駭客攻入資料庫,只能看到無意義的密碼雜湊值,需要花費大量的時間和NSA資源才能破解。

雜湊演算法有很多種(如md5、SHA1、bcrypt和scrypt),有些演算法速度很快,用於驗證資料完整性;有些演算法的速度則很慢,旨在提高安全性。生成密碼和儲存密碼時要使用速度慢、安全性高的演算法。

目前,最安全的演算法當屬bcrypt,與md5和SHA1不同,bcrypt故意設計得很慢,bcrypt會自動加鹽(salt),防止潛在的彩虹表攻擊,bcrypt演算法會花費大量時間反復處理資料,生成特別安全的雜湊值。在這個過程中,處理資料的次數叫工作因子,工作因子的值越高,破解密碼所需的時間越長,安全性越好。bcrypt演算法永不過時,如果計算機運算速度變快了,我們只需提高工作因子的值。

3、密碼雜湊API

通過前面的介紹,我們知道在處理使用者的密碼時要考慮很多東西,好在PHP 5.5.0原生的雜湊API(http://php.net/manual/zh/book.password.php)提供了很多易於使用的函數,大大簡化了計算密碼雜湊值和驗證密碼的操作,而且,這個密碼雜湊API預設使用bcrpt演算法。

開發Web應用時,有兩個地方會用到密碼雜湊API:註冊使用者和使用者登入,下面我們以Laravel提供的使用者註冊和登入為例,看看PHP密碼雜湊API時如何簡化這兩個操作的。

註:Laraval框架內建的使用者註冊和登入功能正是使用了PHP雜湊API實現密碼的儲存和驗證。

註冊使用者

使用者註冊在AuthController中完成,新使用者的建立在該控制器的create方法中實現:

278ab89b7ff2f03a10d20d8389a5aa6.png

可以看到這裡使用了Laravel提供的輔助函數bcrypt對使用者提交的密碼進行雜湊並儲存到資料庫。bcrypt函數定義如下:

07cb77bb1034e8402d4f564bf831b58.png

這裡我們可以看出實際上是呼叫了別名為hash的服務提供者範例上的make方法實現雜湊密碼,進入HashServiceProvider,在register方法中我們可以看到hash對應的類為BcryptHasher,在該類中我們找到了make方法:

adabf5328e0d4f44347ce000e23ac7d.png

這裡的核心是呼叫了PHP提供的password_hash函數,該函數接收三個引數,第一個是使用者輸入的密碼值,第二個引數是使用的雜湊演算法(更多演算法檢視:http://php.net/manual/zh/password.constants.php),第三個引數可選,包括salt和cost兩個選項,分別表示干擾字串(加鹽)和前面提到的工作因子,工作因子可以隨著硬體效能的提升而提升,不傳的話使用隨機加鹽和預設工作因子(計算雜湊值一般需要0.1~0.5s)。如果計算失敗,丟擲異常。

使用者登入

在Larval中以在auth.php中使用session作為guards、eloquent作為providers實現使用者登入認證為例(實際上預設設定就是這樣),登入驗證最終會走到EloquentUserProvider的validateCredentials方法:

85cdb592f5db3e25b83ad7b9776cabc.png

$this->hasher對應的實現也是BcryptHasher類,我們來檢視它的check方法:

bcaaae5bdeae4ed0793c1c47d36354d.png

其中傳入的第一個引數是使用者輸入的密碼,第二個引數是使用者註冊時儲存的密碼雜湊值,如果雜湊值為空直接返回false,否則呼叫php提供的password_verify函數,該函數用於驗證密碼(純文字)和雜湊值是否匹配,匹配返回true,否則返回false。

重新計算雜湊值

通過上述步驟使用者已經可以實現登入認證了,但是登入前我們還需要檢查現有的密碼雜湊值是否已經過期,如果過期,需要重新計算密碼雜湊值。

為什麼要重新計算呢?加入我們的應用建立於兩年前,那時候使用的工作因子時10,現在使用的是20,因為計算機的速度更快了,駭客也更聰明了。可以有些使用者的密碼雜湊值仍然是工作因子為10時生成的,這時,登入認證通過後,要使用password_needs_refresh函數檢查使用者記錄中現有的雜湊值是否需要更新,這個函數可以確保指定的密碼雜湊值是使用最新的雜湊演算法建立的。如果確實需要重新計算生成密碼的雜湊值,要使用make方法生成新的雜湊值並更新資料庫中的原密碼。

Laraval中目前並沒有使用這一功能,但是在BcryptHasher類中已經提供了對應的函數:

edab18a42af7e4dc21eb8254c8c0725.png

原文地址:https://xueyuanjun.com/post/4764

以上就是PHP開發者如何做好密碼保護以及Laravel底層密碼儲存和驗證實現的詳細內容,更多請關注TW511.COM其它相關文章!