您好,登錄后才能下訂單哦!
這篇文章主要介紹“web開發中密碼加密存儲技術有哪些”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“web開發中密碼加密存儲技術有哪些”文章能幫助大家解決問題。
從最早的明文保存密碼,到md5 sha1 sha256 sha512加密,到加salt、加pepper、多次hash計算,再到現代的密碼加密算法Bcrypt PBKDF2 Argon2id。在保護用戶密碼的過程中,軟件工程師作出了巨大的努力,為網絡安全的建設添磚加瓦。
大多數用戶在不同的網站或應用中使用相同的密碼,因此當網站的數據庫被盜取,存儲的密碼也不應該被攻擊者獲取。與密碼學大多數領域一樣,需要考慮很多因素;幸運的是,大多數現代編程語言和框架都提供了內置的功能來幫助存儲密碼,讓問題變得簡單很多。
哈希和加密是兩個經常被混淆或錯誤使用的術語。它們之間的主要區別在于哈希是單向的(不可能“解密”哈希值并獲得原始值),而加密是雙向的。
在幾乎所有情況下,都應該對密碼進行哈希處理而不是加密,因為這會使攻擊者很難或不可能從哈希中獲取原始密碼。
只有在必須獲取原始密碼的極端情況下才使用加密。可能需要這樣做的一些情景是:
如果應用程序需要使用密碼對不支持單獨登錄(SSO)的外部遺留系統進行身份驗證。
如果需要從密碼中檢索單個字符。
能夠解密密碼意為著嚴重的安全風險,因此應進行充分的風險評估。在可能的情況下,應使用其它代替方案,以避免需要以加密形式存儲密碼。
本文章專注于密碼哈希,有關加密密碼的更多指導,請參閱Cryptographic Storage Cheat Sheet。
盡管無法“解密”密碼散列以獲得原始密碼,但是在某些情況下可以“破解”哈希。基本步驟是:
選擇一個常用的密碼(例如“password”)。
計算輸入的哈希值。
將其與目標哈希值進行比較。
使用所有候選密碼重復此過程,直到找到匹配項。有很多不同的方法可用于選擇候選密碼,包括:
暴力破解(嘗試所有可能的密碼)。
常用密碼的詞典或單詞表。
從其它被攻擊站點獲得的密碼列表。
Markov chains或PRINCE之類的更復雜的算法。
常用模式(例如“1個大寫字母,6個小寫字母,1個數字”)。
每個salt都是獨一無二的,隨機生成的字符串,在哈希過程中添加到每個密碼中。由于salt對于每個用戶而言都是唯一的,因此攻擊者對每一個密碼都必須使用相應的salt進行破解,而不能一次性破解整個數據庫的密碼。這使得破解大量哈希變得非常困難,所需時間與哈希數量成正比增長。
salt還可以防止攻擊者使用預先計算的彩虹表。最后,使用salt意味著無法在不破解哈希的情況下確定兩個用戶是否具有相同的密碼,因為即使密碼相同,不同的salt也會導致不同的哈希。
Argon2或Bcrypt之類的現代哈希算法會自動對密碼加salt,因此使用它們時無需其他步驟。 但是,如果您使用的是舊式密碼哈希算法,則需要手動實施加鹽。執行此操作的基本步驟是:
使用安全隨機數生成鹽。使用java.security.SecureRandom,而不是java.util.Random()。
鹽的長度至少應為16個字符。
將鹽編碼為安全字符集,例如hexadecimal或Base64。
結合salt和密碼。
可以使用簡單的拼接或HMAC來完成。
對組合后的密碼和salt進行哈希運算。
存儲哈希值。
安全隨機數的生成方法
除了加salt,還可以加pepper以提供額外的保護。它類似于salt,但有四個主要區別:
所有密碼共享pepper,不像鹽一樣對每個密碼都是唯一的。這使得pepper可預測,并可嘗試破解密碼。pepper的靜態特性也“減弱了”哈希抗沖突的能力,而salt則使用獨一無二的字符串來擴展長度,提高了哈希抗沖突能力,增加了對哈希函數的輸入熵。
pepper不存儲在數據庫中,不像salt一樣(但salt也并非總是如此)。
pepper并不是使密碼破解變得過于困難使攻擊變得不可行,這是其它許多密碼存儲保護措施(如salt)的目標。
salt可防止攻擊者制作已知密碼的彩虹表,但是pepper沒有這樣的作用。
pepper的目的是防止攻擊者僅獲得數據庫時(例如,如果他們利用SQL注入漏洞或獲得數據庫的備份)便無法破解任何哈希。
pepper的長度不應少于32個字符,并使用安全隨機生成器(CSPRNG)隨機生成(如:java.security.SecureRandom)。應該使用安全訪問API將它安全地存儲在“秘密文件庫”中(不能放在應用的配置文件中,因為容易受到SSRF的攻擊),或者將pepper存儲在硬件安全模塊(HSM)中,以獲得最佳的安全保障。
pepper的用法和salt類似,在hash之前將papper和密碼拼接起來,如hash($pepper . $password)。salt可以用拼接的方式,但papper只能以前綴的形式拼接。不要將papper作為后綴,因為這可能會導致諸如與截斷和長度擴展攻擊有關的漏洞。這些威脅使密碼通過驗證,因為獨一無二的密碼永遠不會被截斷,只有papper會被截斷。
備選方案
pepper的另一種可選方案是,照常hash密碼然后使用對稱加密對hash進行加密,加密后再保存到數據庫中。這種加密充當pepper,以不直接影響密碼或hash的方式發揮作用。這避免了拼接/前綴方法的已知問題,并且如果您認為pepper已被泄露,在您更換pepper密鑰時,它允許密碼保持有效。
另一個解決方案是以ID的方式存儲pepper。當存儲密碼時,將關聯的pepperID一起保存到數據庫中。這樣可以做到更換pepper時,不會泄露pepper。當需要更換pepper時,可以使用新的pepperID替換之前的值。這要求應用程序將pepperID與外部存儲關聯起來。
工作因子是指為每個密碼進行hash運算的次數(通常是2^work次)。工作因子的目的是使計算hash更加費時,從而降低了攻擊者的破解速度。工作因子通常和hash值存儲在一起。
選擇工作因子時,需要在安全性和性能之間取得平衡。較高的工作因子將使hash值更難以被攻擊者破解,但也會使登錄驗證的過程變慢。如果工作因子過高,會降低應用程序的性能,并且攻擊者還可以通過進行大量的登錄嘗試來耗盡服務器的CPU性能,對它進行拒絕服務攻擊。
理想的工作因子沒有黃金法則,它取決于服務器的性能和用戶數量。確定最佳工作因子將需要在實際使用的服務器上進行實驗。通常,計算哈希值應少于一秒鐘,但在流量較高的站點上,則應大大少于此值。
更新工作因子
隨著時間的推移,硬件的性能不斷提升而價格則不斷下降。按照摩爾定律,工作因子每18個月應該加1。
更新工作因子的最常見方法是等用戶下次登錄時,使用新的工作因子重新hash密碼。這意味著不同的密碼具有不同的工作因子,并且如果用戶不重新登錄到應用程序,則可能導致密碼hash永遠無法升級。某些情況下,刪除較舊的密碼,要求用戶在下次登錄時重置密碼可能是適當的,以避免存儲較舊且安全性較低的密碼hash。
在某些情況下,可能不需要原始密碼即可提高hash的工作因子,盡管普通的哈希算法(例如Bcrypt和PBKDF2)不支持此功能。
某些哈希算法(例如Bcrypt)的最大輸入長度為72個字符(有報告稱有的實現甚至更短,但在撰寫本文時尚未確定)。在使用Bcrypt的情況下,最大長度應限制為64個字符,因為它提供了足夠的限制,同時仍允許出現字符串終止問題,并且不能揭示應用程序使用了Bcrypt。
此外,由于現代哈希函數在計算上的非常消耗性能,如果用戶可以提供非常長的密碼,則可能存在拒絕服務漏洞,例如2013年在Django中發布的漏洞。
為了防止這兩個問題,應設置最大密碼長度。對于Bcrypt,應該是64個字符(由于算法和實現方面的限制),而對于其他算法,則應該在64和128個字符之間。
限制最大密碼長度確實會減少密碼空間,但限制為64個字符仍然有至少2^420的密碼空間,攻擊者不可能利用這個進行攻擊。因此,這不會明顯地降低安全性。
預哈希密碼
另一種方法是使用快速算法(例如SHA-256)對用戶提供的密碼進行預哈希處理,然后使用諸如Bcrypt(即bcrypt(sha256($password)))等更安全的算法對所得哈希值進行hash處理。盡管此方法解決了用戶輸入任意長度的密碼,導致哈希算法較慢的問題,但它還引入了一些漏洞,這些漏洞可能使攻擊者更容易破解密碼。
如果攻擊者能夠從兩個不同的站點中獲取密碼哈希,其中一個使用bcrypt(sha256($password))存儲密碼,另一個使用sha256($password),則攻擊者可以使用從第二個站點未經破解的SHA-256哈希作為候選密碼嘗試嘗試從第一個(更安全)站點破解這些哈希。如果在兩個站點之間重復使用密碼,則攻擊者可以有效地剝離Bcrypt層,然后將精力集中在破解更容易的SHA-256哈希上。
使用預哈希時,請確保將第一個hash結果安全地編碼為十六進制或base64,因為如果輸入包含空,則某些哈希算法(例如Bcrypt)可能會以不良方式運行。
由于這些問題,通常首選的方法是限制最大密碼長度。僅在有特定要求的情況下才應執行密碼的預哈希處理,并且已經采取了適當的措施來減輕上述問題。
有許多專門設計用于安全存儲密碼的現代哈希算法。這意味著它們應該很慢(不像MD5和SHA-1這樣設計得很快的算法),并且可以通過更改工作因子來配置它們有多慢。
有三種主要算法:
Argon2id
Argon2是2015年密碼哈希競賽的獲勝者。該算法有三種不同版本,應使用Argon2id變體,因為它提供了一種平衡的方法來抵御旁通道攻擊和基于GPU的攻擊。
Argon2具有三個可以配置的參數,而不是像其它算法只能設置的工作因子,這意味著設置正確的參數更為復雜。如果您無法正確的設置參數,則應該使用Bcrypt之類的更簡單算法。
PBKDF2
PBKDF2是NIST推薦的,并且具有經過FIPS-140驗證的實現。因此,當需要這些算法時,它應該是首選算法。此外,它在.NET框架中是開箱即用的,因此通常在ASP.NET應用程序中使用。
PBKDF2可以基于多種不同的哈希算法與HMAC一起使用。HMAC-SHA-256被NIST廣泛支持并推薦使用。
PBKDF2的工作因子通過循環計算實現,循環次數應至少為10,000(在安全性要求更高的環境中,100,000可能更合適)。
Bcrypt
Bcrypt是得到最廣泛支持的算法,除非有對PBKDF2有特殊的需求或有調優Argon2的知識,否則它應該是默認選擇。
Bcrypt的默認工作因子是10,除非在較舊或性能較差的系統上運行,否則通常應將其提高到12。
在某些情況下,通常是由于使用傳統語言或環境而無法使用現代哈希算法。如果可能,應使用第三方庫來提供這些算法。但是,如果只能使用舊算法,例如MD5和SHA-1,則應該采取許多措施來提高存儲密碼的安全性。
使用最強大的算法(SHA-512 > SHA-256 > SHA-1 > MD5)。
用pepper。
為每個密碼使用唯一的salt,使用安全隨機數生成器生成。
進行多次hash計算(至少10,000次,如果硬件性能好的話,應該更多)。
應該強調的是,這些步驟都不如使用現代哈希算法好,僅在沒有其它選項可用的情況下才應采用這種方法。
對于使用安全性較低的哈希算法(例如MD5或SHA-1)構建的遺留程序,應將這些哈希值升級為更現代和安全的哈希值。當用戶下一次輸入密碼(如登錄)時,使用新算法重新加密它。最好使用戶的當前密碼過期,并要求他們輸入一個新密碼,以使用戶密碼的哈希值對攻擊者而言不再有用。
但是,這種方法意味著舊的(安全性較低)密碼哈希將存儲在數據庫中,直到用戶下次登錄為止,并且可能會無限期地存儲。有兩種主要方法可以解決此問題。
一種方法是使長時間不活動的用戶失效并刪除其密碼哈希值,并要求他們重置密碼以再次登錄。盡管安全,但是這種方法并不是特別用戶友好,并且使大量用戶的密碼過期可能會給支持人員造成麻煩,或者可能被用戶認為是違規的行為。但是,如果在登錄時進行密碼哈希升級與刪除舊密碼哈希之間存在合理的間隔時間,則大多數活動用戶應該已經更改了密碼。
另一種方法是將現有的密碼哈希值作為更安全算法的輸入。例如,如果應用程序最初將密碼存儲為md5($password),則可以輕松將其升級為bcrypt(md5($password))。以這種方式對哈希進行分層可以不用知道原始密碼。但是如“預哈希密碼”部分所述,這種方式會使哈希更容易破解。因此,下次用戶登錄時,應直接使用用戶密碼進行哈希,用于替換舊的密碼哈希值。
編寫自定義的加密代碼(例如哈希算法)確實很困難,并且絕不應該在學術活動之外進行。使用未知算法或定制算法可能帶來的任何潛在好處將大大地被其中存在的弱點所削弱。
不要這樣做(Do not do this)。
public static byte[] hashPassword( final char[] password, final byte[] salt, final int iterations, final int keyLength ) { try { SecretKeyFactory skf = SecretKeyFactory.getInstance( "PBKDF2WithHmacSHA512" ); PBEKeySpec spec = new PBEKeySpec( password, salt, iterations, keyLength ); SecretKey key = skf.generateSecret( spec ); byte[] res = key.getEncoded( ); return res; } catch( NoSuchAlgorithmException | InvalidKeySpecException e ) { throw new RuntimeException( e ); } }
password和salt參數是數組,是由hashPassword函數所決定的。使用后應清除敏感數據(將數組元素設置為零)。
該示例使用Password Based Key Derivation Function 2 (PBKDF2),如前所述。
salt參數應該是隨機數,對每個密碼都是唯一的。長度至少應為32個字節。請記住,將salt與密碼哈希值存儲在一起!
iterations參數指定PBKDF2執行多少次hash計算。值越高越安全。您需要在實際運行的硬件上進行實驗。找到需要半秒才能執行加密運算的值。請記住,將iterations值與密碼哈希值存儲在一起!
256的keyLength是安全的。(生成的是32位的哈希值)
如果示例代碼拋出NoSuchAlgorithmException異常,可以將PBKDF2WithHmacSHA512替換為PBKDF2WithHmacSHA1。兩者都足以勝任這項任務,但是當人們看到“SHA1”時,您可能會受到批評(在PBKDF2之外使用SHA1是不安全的)。
自JDK 1.4版以來,SecretKeyFactory和PBEKeySpec類已成為Java SE的一部分。
關于“web開發中密碼加密存儲技術有哪些”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。