安全面試中的一個(gè)基礎(chǔ)問題:你如何在數(shù)據(jù)庫中存儲(chǔ)密碼?
3分鐘講解。
上周的面試故事
職位:初級安全工程師,剛畢業(yè)。
開始面試。
我:“這里你提到對數(shù)據(jù)安全有很好的理解。你能舉例說明哪些方面的數(shù)據(jù)安全嗎?”
A:“當(dāng)然。例如,當(dāng)我們構(gòu)建一個(gè)系統(tǒng)時(shí),會(huì)有一個(gè)用戶模塊,當(dāng)我們在數(shù)據(jù)庫的用戶表中存儲(chǔ)密碼時(shí),我們需要在存儲(chǔ)之前對其進(jìn)行加密。”
我:“你確定是加密而不是哈希處理嗎?”
A:“是的。”
我:“那你把密鑰存在哪里?”
A:“什么密鑰?”
我:“你用來加密密碼的加密密鑰。是對稱加密還是非對稱加密?每個(gè)用戶都有一個(gè)密鑰還是共享一個(gè)密鑰?”
A:“嗯……我們沒有使用這些。所以應(yīng)該是哈希處理。”
我:“沒關(guān)系。你能解釋一下為什么我們需要在存儲(chǔ)之前進(jìn)行哈希處理,而不是存儲(chǔ)明文嗎?”
A:“是的。因?yàn)槲覀兿胍_保安全。當(dāng)我們驗(yàn)證密碼時(shí),密碼不能以明文形式從UI發(fā)送到服務(wù)器進(jìn)行驗(yàn)證。”
我:“當(dāng)你注冊用戶時(shí),是否需要以明文形式發(fā)送密碼和確認(rèn)密碼?”
A:“是的,但那是唯一一次我們發(fā)送明文。”
我:“好的,我明白你的意思。你認(rèn)為在數(shù)據(jù)庫中存儲(chǔ)哈希值的原因是為了減少在API調(diào)用期間發(fā)送敏感數(shù)據(jù)為明文的機(jī)會(huì)?”
A:“沒錯(cuò)。”
我:“那么你認(rèn)為當(dāng)數(shù)據(jù)庫被人入侵時(shí),存儲(chǔ)哈希值會(huì)有意義嗎?”
A:“哦,是的,這樣原始密碼就不會(huì)被黑客看到。哈希值可以防止這一點(diǎn)。”
我:“是的,但這還不夠。有人仍然可能使用彩虹表攻擊,通過哈希碰撞得到原始值。你知道什么是鹽(salt)嗎?”
A:“聽說過。值應(yīng)該是一個(gè)隨機(jī)字符串,這會(huì)使密碼存儲(chǔ)更安全。”
我:“很好。你知道它是如何工作的嗎?”
A:“不太清楚。”
我:“假設(shè)有人通過SQL注入或其他方式獲取了數(shù)據(jù)庫,然后使用彩虹表進(jìn)行攻擊,發(fā)生哈希碰撞并得到了原始文本,但他得到的是混合了隨機(jī)字符串的原始密碼,這樣我們可以防止原始密碼被竊取。這意味著我們阻止了一些人獲取你的‘一鍵登錄’密碼來登錄你的郵件、社交媒體甚至銀行賬戶。”
A:“我明白了。”
我:“那么你們目前系統(tǒng)中使用的是哪種哈希算法?”
A:“我們知道m(xù)d5不安全,所以我們使用了其他選項(xiàng),比如sha3。”
我:“你能簡要說明一下為什么md5不安全嗎?為什么選擇sha3來哈希密碼?因?yàn)閾?jù)我所知,sha3的KDF(如hmac-sha3)并不是為哈希密碼設(shè)計(jì)的,而是用于其他用途,如JWT令牌簽名。”
A:“md5被證明是不安全的,已經(jīng)有一些報(bào)道。但是KDF是什么?”
我:“KDF是密鑰派生函數(shù)。這意味著你使用的哈希算法會(huì)將密碼作為輸入生成哈希值。是的,有報(bào)道說md5不安全。但你知道為什么嗎?”
A:“嗯,不太清楚。”
我:“簡而言之,這是因?yàn)樗墓E鲎驳挚沽θ酰赡鼙徊屎绫砉簟!?/p>
A:“什么是彩虹表?”
我:“彩虹表是一種預(yù)計(jì)算的表格,包含從明文密碼派生的哈希值鏈。這些鏈通過反復(fù)應(yīng)用哈希函數(shù)生成,然后通過一系列還原函數(shù)將結(jié)果哈希值還原為明文密碼。彩虹表通常用于密碼破解攻擊中,攻擊者將存儲(chǔ)在被入侵?jǐn)?shù)據(jù)庫中的哈希密碼與彩虹表中的條目進(jìn)行比較,以找到匹配的明文密碼。”
A:“我明白了。”
我:“那你為什么使用sha3來生成密碼?”
A:“我覺得它比MD5更安全。”
我:“是的,但可能有更好的密碼哈希選項(xiàng)。比如2015年獲獎(jiǎng)的argon2,比sha3需要更多的迭代和更高的RAM,這意味著更高的時(shí)間復(fù)雜度和資源消耗,從而使攻擊者更難以進(jìn)行暴力破解。但sha3通常用于其他用途,例如數(shù)字簽名,平衡安全性和性能。”
……
讓我們逐個(gè)分析這個(gè)面試中的細(xì)節(jié)。
密碼哈希
我們都知道,在21世紀(jì),密碼絕不能以明文形式保存。
然而,這不僅僅是為了減少在某些API調(diào)用期間發(fā)送密碼值為明文的機(jī)會(huì)。 主要的關(guān)注點(diǎn)是當(dāng)數(shù)據(jù)庫落入壞人之手時(shí),使其無法恢復(fù)原始文本。 接下來發(fā)生的事情是數(shù)據(jù)庫將被“憑證填充攻擊”。相同的憑證會(huì)在不同的賬戶上反復(fù)嘗試:電子郵件、銀行卡、社交媒體、學(xué)校,甚至是政府賬戶。
為什么不使用加密而是哈希?
關(guān)鍵區(qū)別在于可逆性。加密是一個(gè)可逆的過程,這意味著使用正確的密鑰可以恢復(fù)原始的明文密碼。這構(gòu)成了一個(gè)安全風(fēng)險(xiǎn),即使加密密鑰被安全管理。 此外,管理加密密鑰,如構(gòu)建密鑰鏈,可能會(huì)帶來顯著的成本和復(fù)雜性。
為什么需要鹽(salt)
鹽用于為每個(gè)哈希密碼添加隨機(jī)性,使攻擊者使用預(yù)計(jì)算表如彩虹表來破解密碼變得計(jì)算上昂貴。 沒有鹽,攻擊者可以通過將哈希值與大型預(yù)計(jì)算哈希數(shù)據(jù)庫進(jìn)行比較來有效猜測密碼。 此外,鹽必須對每個(gè)密碼唯一,而不僅僅是對每個(gè)用戶唯一。這確保即使兩個(gè)用戶有相同的密碼,由于唯一的鹽,他們的哈希值也會(huì)不同,防止攻擊者輕易識別重復(fù)的密碼。
不同用途的哈希
Sha3比md5更安全,為什么不使用sha3?哈希不僅用于密碼值,還有不同的使用場景:
- 數(shù)據(jù)完整性(如SHA3):哈希算法如SHA3通常用于指紋文件,確保其完整性保持不變。這些算法需要在速度和哈希碰撞抵抗之間找到平衡。雖然SHA3提供了良好的碰撞抵抗,但它也保持了文件指紋任務(wù)的合理性能。
- 校驗(yàn)和(如CRC32):當(dāng)速度至關(guān)重要時(shí),如在網(wǎng)絡(luò)傳輸期間驗(yàn)證數(shù)據(jù)完整性,CRC32等算法表現(xiàn)出色。CRC32通常用于快速識別文件在傳輸過程中是否被修改,優(yōu)先考慮效率而不是碰撞抵抗。
- 密鑰生成(如Argon2、bcrypt、PBKDF2):為了安全地存儲(chǔ)密碼或生成加密密鑰,首選專門的密鑰派生函數(shù)(KDF)如Argon2、bcrypt或PBKDF2。這些算法故意引入“慢”哈希過程,通過增加計(jì)算復(fù)雜性來抵御哈希碰撞的暴力破解。
雖然SHA3適用于HTTPS連接或JWT令牌簽名生成等任務(wù),但它缺乏提供密碼哈希所需的必要“慢”特性。
為什么KDF在密碼哈希中很重要
KDF在密碼哈希中通過故意減慢哈希過程起著關(guān)鍵作用。這種故意的減慢是通過多次迭代哈希值計(jì)算實(shí)現(xiàn)的。雖然這些迭代的技術(shù)細(xì)節(jié)可能很復(fù)雜,但它們本質(zhì)上涉及重復(fù)操作如移位、反轉(zhuǎn)和XOR-ing哈希值,執(zhí)行數(shù)千輪。
使用KDF哈希密碼的主要目標(biāo)是:
- 減慢過程:通過引入計(jì)算開銷,KDF使攻擊者更難以暴力破解密碼。計(jì)算哈希值所需的時(shí)間和資源增加,作為快速詞典或彩虹表攻擊的威懾。
- 資源消耗:KDF在哈希過程中還會(huì)消耗大量的CPU和內(nèi)存資源。這種資源密集型特性進(jìn)一步阻礙了攻擊者,因?yàn)樗麄儽仨毻度氪罅康挠?jì)算能力和時(shí)間來破解哈希密碼。
什么是彩虹表攻擊?
簡要解釋:
- 詞典表:在彩虹表之前,攻擊者預(yù)計(jì)算所有哈希值,并在一個(gè)稱為“詞典表”的表中枚舉所有哈希值。然后,在獲取目標(biāo)數(shù)據(jù)庫表后,進(jìn)行哈希碰撞并得到關(guān)聯(lián)的原始密碼值(這也是為什么鹽如此重要)。
- 然而,詞典表可能會(huì)迅速增長,最終包含大量行,變得不可用。
- 彩虹表可以被視為“詞典表的高效版本”。
- 在彩虹表中,有兩個(gè)函數(shù)。H:從明文獲取哈希值,R:從哈希值獲取明文。
- 存儲(chǔ)多行,每行是一個(gè)“哈希鏈”,每行從一個(gè)明文開始,然后多次進(jìn)行H和R。
- 對目標(biāo)數(shù)據(jù)庫表進(jìn)行哈希碰撞,一旦哈希值匹配,進(jìn)行R以獲取明文。
最后
為什么md5(或sha1)不能用于密碼哈希?如果可以,md5還有其他用途嗎?
簡單回答:弱哈希碰撞抵抗。
- md5在2004年被證明具有弱哈希碰撞抵抗。
- sha1也在2005年被證明具有相同的問題,并由谷歌在2017年宣布。
- 我們可以將md5用于其他用途嗎?比如指紋或校驗(yàn)和?不行。已被證明,兩個(gè)不同的文件可以生成相同的md5;如果用于校驗(yàn)和,crc32具有更快的性能。
- md5沒有使用場景,你永遠(yuǎn)不應(yīng)該使用它。























