自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

密碼存儲中MD5的安全問題與替代方案

開發(fā)
經(jīng)過各種安全事件后,很多系統(tǒng)在存放密碼的時候不會直接存放明文密碼了,大都改成了存放了 md5 加密(hash)后的密碼,可是這樣真的安全嗎?

密碼存儲中MD5的安全問題與替代方案

md5安全嗎?有多么地不安全?如何才能安全地存儲密碼?…

md5安全嗎?

經(jīng)過各種安全事件后,很多系統(tǒng)在存放密碼的時候不會直接存放明文密碼了,大都改成了存放了 md5 加密(hash)后的密碼,可是這樣真的安全嗎?

這兒有個腳本來測試下MD5的速度, 測試結(jié)果:

  1. [root@f4d5945f1d7c tools]# php speed-of-md5.php 
  2. Array 
  3.     [rounds] => 100 
  4.     [times of a round] => 1000000 
  5.     [avg] => 0.23415904045105 
  6.     [max] => 0.28906106948853 
  7.     [min] => 0.21188998222351 
  8.  

有沒有發(fā)現(xiàn)一個問題:MD5速度太快了,導(dǎo)致很容易進(jìn)行暴力破解.

簡單計算一下:

  1. > Math.pow(10, 6) / 1000000 * 0.234 
  2. 0.234 
  3. > Math.pow(36, 6) / 1000000 * 0.234 / 60 
  4. 8.489451110400001 
  5. > Math.pow(62, 6) / 1000000 * 0.234 / 60 / 60 
  6. 3.69201531296  
  1. 使用6位純數(shù)字密碼,破解只要0.234秒!
  2. 使用6位數(shù)字+小寫字母密碼,破解只要8.49分鐘!
  3. 使用6位數(shù)字+大小寫混合字母密碼,破解只要3.69個小時!

當(dāng)然,使用長一點的密碼會顯著提高破解難度:

  1. > Math.pow(10, 8) / 1000000 * 0.234 
  2. 23.400000000000002 
  3. > Math.pow(36, 8) / 1000000 * 0.234 / 60 / 60 / 24 
  4. 7.640505999359999 
  5. > Math.pow(62, 8) / 1000000 * 0.234 / 60 / 60 / 24 / 365 
  6. 1.6201035231755982  
  1. 使用8位純數(shù)字密碼,破解要23.4秒!
  2. 使用8位數(shù)字+小寫字母密碼,破解要7.64小時!
  3. 使用8位數(shù)字+大小寫混合字母密碼,破解要1.62年!

但是,別忘了,這個速度只是用PHP這個解釋型語言在筆者的弱雞個人電腦(i5-4460 CPU 3.20GHz)上跑出來的,還只是利用了一個線程一個CPU核心。若是放到最新的 Xeon E7 v4系列CPU的服務(wù)器上跑,充分利用其48個線程,并使用C語言來重寫下測試代碼,很容易就能提升個幾百上千倍速度。那么即使用8位數(shù)字+大小寫混合字母密碼,破解也只要14小時!

更何況,很多人的密碼都是采用比較有規(guī)律的字母或數(shù)字,更能降低暴力破解的難度… 如果沒有加鹽或加固定的鹽,那么彩虹表破解就更easy了…

那么如何提升密碼存儲的安全性呢?bcrypt!

提升安全性就是提升密碼的破解難度,至少讓暴力破解難度提升到攻擊者無法負(fù)擔(dān)的地步。(當(dāng)然用戶密碼的長度當(dāng)然也很重要,建議至少8位,越長越安全)

這里不得不插播一句:PHP果然是世界上最好的語言 — 標(biāo)準(zhǔn)庫里面已經(jīng)給出了解決方案。

PHP 5.5 的版本中加入了 password_xxx 系列函數(shù), 而對之前的版本,也有兼容庫可以用:password_compat.

在這個名叫“密碼散列算法”的核心擴(kuò)展中提供了一系列簡潔明了的對密碼存儲封裝的函數(shù)。簡單介紹下:

  1. password_hash 是對密碼進(jìn)行加密(hash),目前默認(rèn)用(也只能用)bcrypt算法,相當(dāng)于一個加強(qiáng)版的md5函數(shù)
  2. password_verify 是一個驗證密碼的函數(shù),內(nèi)部采用的安全的字符串比較算法,可以預(yù)防基于時間的攻擊, 相當(dāng)于 $hashedPassword === md5($inputPassword)
  3. password_needs_rehash 是判斷是否需要升級的一個函數(shù),這個函數(shù)厲害了,下面再來詳細(xì)講

password_hash 需要傳入一個算法,現(xiàn)在默認(rèn)和可以使用的都只有bcrypt算法,這個算法是怎么樣的一個算法呢?為什么PHP標(biāo)準(zhǔn)庫里面會選擇bcrypt呢?

bcrypt是基于 Blowfish 算法的一種專門用于密碼哈希的算法,由 Niels Provos 和 David Mazieres 設(shè)計的。這個算法的特別之處在于,別的算法都是追求快,這個算法中有一個至關(guān)重要的參數(shù):cost. 正如其名,這個值越大,耗費的時間越長,而且是指數(shù)級增長 — 其加密流程中有一部分是這樣的:

  1. EksBlowfishSetup(cost, salt, key
  2.     state <- InitState() 
  3.     state <- ExpandKey(state, salt, key
  4.     repeat (2^cost)                         // "^"表示指數(shù)關(guān)系 
  5.         state <- ExpandKey(state, 0, key
  6.         state <- ExpandKey(state, 0, salt) 
  7.     return state  

比如下面是筆者的一次測試結(jié)果(個人弱機(jī)PC, i5-4460 CPU 3.20GHz) :

  1. cost       time 
  2.          8   0.021307 
  3.          9   0.037150 
  4.         10   0.079283 
  5.         11   0.175612 
  6.         12   0.317375 
  7.         13   0.663080 
  8.         14   1.330451 
  9.         15   2.245152 
  10.         16   4.291169 
  11.         17   8.318790 
  12.         18  16.472902 
  13.         19  35.146999  

附:測試代碼

這個速度與md5相比簡直是蝸牛與獵豹的差別 — 即使按照cost=8, 一個8位的大小寫字母+數(shù)字的密碼也要14萬年才能暴力破解掉,更何況一般服務(wù)器都會至少設(shè)置為10或更大的值(那就需要54萬年或更久了)。

顯然,cost不是越大越好,越大的話會越占用服務(wù)器的CPU,反而容易引起DOS攻擊。建議根據(jù)服務(wù)器的配置和業(yè)務(wù)的需求設(shè)置為10~12即可。最好同時對同一IP同一用戶的登錄嘗試次數(shù)做限制,預(yù)防DOS攻擊。

一個安全地存儲密碼的方案

總上所述,一個安全地存儲密碼的方案應(yīng)該是這樣子的:(直接放代碼吧)

  1. class User extends BaseModel 
  2.     const PASSWORD_COST = 11; // 這里配置bcrypt算法的代價,根據(jù)需要來隨時升級 
  3.     const PASSWORD_ALGO = PASSWORD_BCRYPT; // 默認(rèn)使用(現(xiàn)在也只能用)bcrypt 
  4.  
  5.     /** 
  6.     * 驗證密碼是否正確 
  7.     * 
  8.     * @param string $plainPassword 用戶密碼的明文 
  9.     * @param bool  $autoRehash    是否自動重新計算下密碼的hash值(如果有必要的話) 
  10.     * @return bool 
  11.     */ 
  12.     public function verifyPassword($plainPassword, $autoRehash = true
  13.     { 
  14.         if (password_verify($plainPassword, $this->password)) { 
  15.             if ($autoRehash && password_needs_rehash($this->password, self::PASSWORD_ALGO, ['cost' => self::PASSWORD_COST])) { 
  16.                 $this->updatePassword($plainPassword); 
  17.             } 
  18.  
  19.             return true
  20.         } 
  21.  
  22.         return false
  23.     } 
  24.  
  25.     /** 
  26.     * 更新密碼 
  27.     * 
  28.     * @param string $newPlainPassword 
  29.     */ 
  30.     public function updatePassword($newPlainPassword) 
  31.     { 
  32.         $this->password = password_hash($newPlainPassword, self::PASSWORD_ALGO, ['cost' => self::PASSWORD_COST]); 
  33.         $this->save(); 
  34.     } 
  35.  

這樣子,在用戶注冊或修改密碼的時候就調(diào)用 $user->updatePassword() 來設(shè)置密碼,而登錄的時候就調(diào)用 $user->verifyPassword() 來驗證下密碼是否正確。

當(dāng)硬件性能提升到一定程度,而cost=11無法滿足安全需求的時候,則修改下 PASSWORD_COST 的值即可無縫升級,讓存放的密碼更安全。 

責(zé)任編輯:龐桂玉 來源: Android開發(fā)中文站
相關(guān)推薦

2015-03-23 11:21:08

2022-10-18 22:21:51

2009-11-03 13:46:56

Oracle密碼

2010-04-02 13:53:47

2016-12-15 09:26:53

MD5加密

2021-12-06 18:16:14

SQLCRCMD5

2009-05-05 17:52:48

系統(tǒng)安全密碼安全Windows

2019-06-14 05:00:05

2009-04-27 10:39:47

視頻會議存儲安全

2009-06-06 18:57:47

MD5加密類Java Bean

2020-10-15 08:20:52

MD5算法加密的過程

2010-05-04 17:43:50

Unix系統(tǒng)

2013-04-02 13:06:20

BYODBYOD安全

2011-12-28 13:14:39

2012-05-30 16:25:30

密碼安全

2010-03-16 09:27:31

2012-11-20 10:47:16

2011-07-14 14:21:11

2013-08-14 09:11:43

云數(shù)據(jù)存儲云存儲云安全

2014-07-28 11:18:30

件測試云計算云測試
點贊
收藏

51CTO技術(shù)棧公眾號