隨著網路攻擊的增多,密碼安全越來越重要。身為開發者我們要擔負起安全管理、計算雜湊和儲存使用者密碼的責任,不管應用程式是簡單的遊戲還是絕密商業文件的倉庫,都要做到這一點。 PHP內建了一些工具,讓保護密碼變得更容易,本節我們就來討論如何根據現代的安全措施來使用這些工具。
1、密碼保護三原則
絕對不能知道使用者的密碼
我們絕對不能知道使用者的密碼,也不能有取得使用者密碼的方式,如果應用的資料庫被黑,你一定不希望資料庫中有純文字或能解密的密碼。任何時候,知道的越少越安全。
絕對不要約束使用者的密碼
如果要求密碼符合特定的模式,其實是為不懷好意的人提供了攻擊應用的途徑,如果必須約束密碼,我建議只限制最小長度,把常用的密碼或基於字典創建的密碼加入黑名單也是個好主意。
絕對不能透過電子郵件傳送使用者密碼
如果你透過電子郵件給使用者密碼,使用者會知道三件事:你知道他的密碼,你使用純文字或能解密的方式儲存了他的密碼,你沒有對透過網路發送純文字的密碼感到不安。
我們應該在電子郵件中發送用於設定或修改密碼的URL,網路應用程式通常會產生一個唯一的令牌,這個令牌只在設定或修改密碼時使用一次(例如修改密碼),通常我們把這個令牌當作設定或修改密碼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方法中實現:
可以看到這裡使用了Laravel提供的輔助函數bcrypt對使用者提交的密碼進行雜湊並儲存到資料庫。 bcrypt函數定義如下:
這裡我們可以看出實際上是呼叫了別名為hash的服務提供者實例上的make方法實作雜湊密碼,進入HashServiceProvider,在register方法中我們可以看到hash對應的類別為BcryptHasher,在該類別中我們找到了make方法:
這裡的核心是呼叫了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方法:
$this->hasher對應的實作也是BcryptHasher類,我們來查看它的check方法:
其中傳入的第一個參數是使用者輸入的密碼,第二個參數是使用者註冊時儲存的密碼雜湊值,如果雜湊值為空直接傳回false,否則呼叫php提供的password_verify函數,該函數用於驗證密碼(純文字)和雜湊值是否匹配,匹配返回true,否則傳回false。
重新計算雜湊值
透過上述步驟使用者已經可以實現登入認證了,但是登入前我們還需要檢查現有的密碼雜湊值是否已經過期,如果過期,需要重新計算密碼雜湊值。
為什麼要重新計算呢?加入我們的應用程式創建於兩年前,那時使用的工作因子時10,現在使用的是20,因為電腦的速度更快了,駭客也更聰明了。可以有些使用者的密碼雜湊值仍然是工作因子為10時產生的,這時,登入認證通過後,要使用password_needs_refresh函數檢查使用者記錄中現有的雜湊值是否需要更新,這個函數可以確保指定的密碼哈希值是使用最新的哈希演算法創建的。如果確實需要重新計算產生密碼的雜湊值,請使用make方法產生新的雜湊值並更新資料庫中的原密碼。
Laraval目前並沒有使用這項功能,但在BcryptHasher類別中已經提供了對應的函數:
#原文位址:https ://xueyuanjun.com/post/4764
以上是PHP開發者如何做好密碼保護以及Laravel底層密碼儲存和驗證實現的詳細內容。更多資訊請關注PHP中文網其他相關文章!