不行。存儲在數據庫的數據面臨不少威脅,有應用程序層面、數據庫層面的、操做系統層面的、機房層面的、員工層面的,想作到百分百不被黑客竊取,很是困難。算法
若是密碼是加密以後再存儲,那麼即使被拖庫,黑客也難以獲取用戶的明文密碼。能夠說,密碼加密存儲是用戶帳戶系統的底褲,它的重要性,至關於你獨自出遠門時縫在內衣裏錢,雖然你用到他們的機率不大,但關鍵時刻他們能救命。數據庫
不行。這涉及到怎麼保存用來加密解密的密鑰,雖然密鑰通常跟用戶信息分開存儲,且業界也有一些成熟的、基於軟件或硬件的密鑰存儲方案。但跟用戶信息的保存同樣,想要密鑰百分百不泄露,不可能作到。用這種方式加密密碼,可以下降黑客獲取明文密碼的機率。但密鑰一旦泄露,用戶的明文密碼也就泄露了,不是一個好方法。編程
另外,用戶帳戶系統不該該保存用戶的明文密碼,在用戶忘記密碼的時候,提供重置密碼的功能而不是找回密碼。安全
不是全部的HASH算法均可以,準確講應該是Cryptographic Hash。Cryptographic Hash具備以下幾個特色:服務器
雖然不是爲加密密碼而設計,但其第二、三、4三個特性使得Cryptographic Hash很是適合用來加密用戶密碼。常見的Cryptographic Hash有MD五、SHA-一、SHA-二、SHA-3/Keccak、BLAKE2。dom
從1976年開始,業界開始使用Cryptographic Hash加密用戶密碼,最先見於Unix Crypt。但MD五、SHA-1已被破解,不適合再用來保存密碼。編程語言
不行。黑客能夠用查詢表或彩虹表來破解用戶密碼。注意是破解密碼不是破解sha256,能根據sha256破解密碼的緣由是,用戶密碼每每須要大腦記憶、手工輸入,因此不會太複雜,每每具備有限的長度、肯定的取值空間。函數
好比8位數字密碼,一共只有10^8=100000000種可能。一億條數據並不算多,黑客能夠提早吧0-99999999的sha256都計算好,並以sha256作key密碼爲value存儲爲一個查詢表,當給定sha256須要破解時,從表中查詢便可。優化
好比10位,容許數字、字母大小寫的密碼,一共有(10+26+26)^10~=84億億種可能,記錄很是之多難以用查詢表所有保存起來。這時候黑客會用一種叫作彩虹表的技術來破解,彩虹表用了典型的計算機世界裏解決問題的思路,時間空間妥協。在這個例子裏面,空間不夠,那就多花一些時間。在彩虹表中,能夠將所有的sha256值轉化爲長度相同的若干條hash鏈,只保存hash鏈的頭和尾,在破解的時候先查詢獲得sha256存在於哪條hash鏈中,而後計算這一條hash鏈上的全部sha256,經過實時比對來破解用戶密碼。ui
上圖圖展現了一個hash鏈長度爲3的彩虹表,由於在hash鏈中須要將hash值使用R函數映射回密碼取值空間,爲了下降R函數的衝突機率,長度爲K的hash鏈中,彩虹表會使用k個R函數,由於每次迭代映射回密碼空間使用的R函數不同,這種破解方法被稱做彩虹表攻擊。
實際的狀況Hash鏈要比遠比上例更長,好比咱們的例子中所有的84億億個sha256存不下,能夠轉化爲840億條長度爲1千萬的sha鏈。對彩虹表原理感興趣的話,能夠閱讀它的維基百科。
網路上甚至有一些已經計算好的彩虹表能夠直接使用,因此直接保存用戶密碼的sha256是很是不安全的。
簡單講,就是加鹽。通常來說用戶密碼是個字符串key、鹽是咱們生成的字符串salt。原來咱們保存的是key的hash值HASH(key),如今咱們保存key和salt拼接在一塊兒的hash值HASH(key+salt)。
這樣黑客提早計算生成的彩虹表,就全都失效了。
這是個好問題,並非加個鹽就安全了,鹽的生成有不少講究。
CSPRNG跟普通的隨機數生成算法,好比C語言標準庫裏面的rand()方法,有很大不一樣。正如它的名字所揭示,CSPRNG是加密安全的,這意味着用它產生的隨機數更加隨機,且不可預測。常見編程語言都提供了CSPRNG,以下表:
編程語言 | CSPRNG |
---|---|
C/C++ | CryptGenRandom |
Java | Java.security.SecureRandom |
PHP | mcrypt_create_iv |
Erlang | Crypt:strong_rand_bytes |
Linux/Unix上的任何編程語言 | 讀取/dev/random |
想一想查詢表和彩虹表的原理,若是鹽很短,那意味着密碼+鹽組成的字符串的長度和取值空間都有限。黑客徹底能夠爲密碼+鹽的全部組合創建彩虹表。
若是全部用戶的密碼都使用同一個鹽進行加密。那麼無論鹽有多複雜、多大的長度,黑客均可以很容易的使用這個固定鹽從新創建彩虹表,破解你的全部用戶的密碼。若是你說,我能夠把固定鹽存起來,不讓別人知道啊,那麼你應該從新讀一下我關於爲何使用AES加密不夠安全的回答。
即使你爲每個用戶生成一個隨機鹽,安全性仍然不夠,由於這個鹽在用戶修改密碼時重複使用了。應當在每一次須要保存新的密碼時,都生成一個新的鹽,並跟加密後的hash值保存在一塊兒。
注意:有些系統用一個每一個用戶都不一樣的字段,uid、手機號、或者別的什麼,來做爲鹽加密密碼。這不是一個好主意,這幾乎違背了上面所有三條鹽的生成規則。
不能夠。
首先若是你不是一個密碼學專家,你很難設計出一個安全的hash算法。不服氣的話,你能夠再看一遍上面我關於Cryptographic Hash的描述,而後想想本身怎麼設計一個算法能夠知足它的所有四種特性。就算你是基於已有的Cryptographic Hash的基礎上去設計,設計完以後,也難以保證新算法仍然知足Cryptographic Hash的要求。而一旦你的算法不知足安全要求,那麼你給了黑客更多更容易破解用戶密碼的方法。
即使你能設計出一個別人不知道的Cryptographic Hash算法,你也不能保證黑客永遠都不知道你的算法。黑客每每都有能力訪問你的代碼,想一想柯克霍夫原則或者香農千米:
密碼系統應該就算被全部人知道系統的運做步驟,仍然是安全的。
之前是能夠的,如今不行了。 計算機硬件飛速發展,一個現代通用CPU能以每個月數百萬次的速度計算sha256,而GPU集羣計算sha256,更是能夠達到每秒10億次以上。這使得暴力破解密碼成爲可能,黑客再也不依賴查詢表或彩虹表,而是使用定製過的硬件和專用算法,直接計算每一種可能,實時破解用戶密碼。
那怎麼辦呢?回想上面關於Cryptographic Hash特性的描述,其中第一條:
給定任意大小任意類型的輸入,計算hash很是快
Cryptographic Hash並非爲了加密密碼而設計的,它計算很是快的這個特性,在其餘應用場景中很是有用,而在如今的計算機硬件條件下,用來加密密碼就顯得不合適了。針對這一點,密碼學家們設計了PBKDF二、BCRYPT、SCRYPT等用來加密密碼的Hash算法,稱做Password Hash。在他們的算法內部,一般都須要計算Cryptographic Hash不少次,從而減慢Hash的計算速度,增大黑客暴力破解的成本。能夠說Password Hash有一條設計原則,就是計算過程可以按要求變慢,而且不容易被硬件加速。
PBKDF二、BCRYPT、SCRYPT曾經是最經常使用的三種密碼Hash算法,至於哪一種算法最好,多年以來密碼學家們並沒有定論。但能夠肯定的是,這三種算法都不完美,各有缺點。其中PBKDF2由於計算過程須要內存少因此可被GPU/ASIC加速,BCRYPT不支持內存佔用調整且容易被FPGA加速,而SCRYPT不支持單獨調整內存或計算時間佔用且可能被ASIC加速並有被旁路攻擊的可能。
2013年NIST(美國國家標準與技術研究院)邀請了一些密碼學家一塊兒,舉辦了密碼hash算法大賽(Password Hashing Competition),意在尋找一種標準的用來加密密碼的hash算法,並藉此在業界宣傳加密存儲用戶密碼的重要性。大賽列出了參賽算法可能面臨的攻擊手段:
最終在2015年7月,Argon2算法贏得了這項競賽,被NIST認定爲最好的密碼hash算法。不過由於算法過新,目前還沒據說哪家大公司在用Argon2作密碼加密。
今年(2016)Dropbox曾發生部分用戶密碼數據泄露事件,當時其CTO表示他們對本身加密密碼的方式頗有信心,請用戶放心。隨後,Dropbox在其官方技術博客發表名爲《How Dropbox securely stores your passwords》的文章,講述了他們的用戶密碼加密存儲方案。
如上圖所示,Dropbox首先對用戶密碼作了一次sha512哈希將密碼轉化爲64個字節,而後對sha512的結果使用Bcrypt算法(每一個用戶獨立的鹽、強度爲10)計算,最後使用AES算法和全局惟一的密鑰將Bcrypt算法的計算結果加密並保存。博文中,Dropbox描述了這三層加密的緣由: