今天我們在課堂上討論了密碼哈希和加鹽處理。我們的教授對我的鹽的用例有完全不同的理解,並說您可能根本不存儲鹽,而只是檢查所有可能的鹽的每次登錄嘗試並授權是否匹配。
I因為現在我的服務更容易受到蠻力攻擊(發送一個密碼,服務器檢查許多密碼),因此我對此服務沒有任何實質性的了解,但是我猜想它對散列密碼的純字典式攻擊更為安全。
那麼有沒有用例人們會真正做到這一點?
今天我們在課堂上討論了密碼哈希和加鹽處理。我們的教授對我的鹽的用例有完全不同的理解,並說您可能根本不存儲鹽,而只是檢查所有可能的鹽的每次登錄嘗試並授權是否匹配。
I因為現在我的服務更容易受到蠻力攻擊(發送一個密碼,服務器檢查許多密碼),因此我對此服務沒有任何實質性的了解,但是我猜想它對散列密碼的純字典式攻擊更為安全。
那麼有沒有用例人們會真正做到這一點?
不存儲鹽是一個壞建議。
鹽的主要目的是必須分別攻擊每個用戶密碼。
如果不存儲鹽,則就像您說的那樣,您需要嘗試每種單一的鹽組合才能驗證密碼。如果需要檢查每種鹽組合,則意味著鹽不能太長(在註釋中提到了12位)。如果加鹽時間不長,則表示將對許多用戶重複加鹽。如果對許多用戶重複此操作,則意味著攻擊者將能夠同時攻擊許多用戶,這將節省攻擊者的時間。
這樣做,您幾乎完全無法實現使用a鹽。
來自維基百科:
可以在以下位置將胡椒添加到密碼中:除了鹽值。胡椒粉與鹽的作用相似,但是鹽通常與散列的值一起存儲,對於要定義為胡椒粉的東西,它應滿足以下條件之一,將其定義為更精心隱藏的“秘密”比鹽值高:
- 將胡椒與要散列的值分開保存
- 為要散列的每個值隨機生成胡椒(在一組有限的值),並且永遠不會存儲。當針對匹配的哈希值測試數據時,這是通過迭代對胡椒有效的一組值來完成的,然後依次將每個值添加到要測試的數據中(通常通過將其後綴添加到數據中),在對組合值運行加密哈希函數之前。
Pepper的優點是,攻擊者現在必須猜測多達Pepper值的可能排列數量
請記住,鹽是緩解預計算哈希的有效方法,它會使攻擊者花費很長時間攻擊一組哈希。但是,如果僅考慮一個散列,並且不使用任何預先計算的散列,則鹽不會增加攻擊時間。但是,Pepper迫使攻擊者對每個純文本密碼使用多個猜測,即使是單個哈希也是如此。
這樣,胡椒類似於鍵拉伸。
我的個人觀察是,大多數實現方式都喜歡用鍵拉伸而不是胡椒。我沒有相關參考,因此讀者可以在評論中提供支持或反對的參考。人們傾向於使用鍵拉伸,因為它具有已知和預期的性能成本和安全性好處。為了計算哈希的第N輪,必須計算N個哈希。但是,使用胡椒粉只能計算出預期的嘗試次數。考慮一個1字節的胡椒,攻擊者將需要256個猜測才能猜測所有可能的組合,但是期望值為128,並且攻擊者可以(平均1/256倍)猜測第一次嘗試。
鍵拉伸很有效,因為您可以根據希望計算哈希的時間長度來設置回合數採取。假設您希望在當前硬件上進行一次檢查要花費半秒鐘,那麼您只需增加回合數即可,直到出現這種情況為止。
對於胡椒,因為您需要為每個密碼猜測多個值,所以胡椒的大小必須與輪數成反比,以保持計算時間恆定。
關於密碼/哈希實現的最佳建議是使用眾所周知的方法和經過測試的庫。您應該使用 bcrypt或 pbkdf2並加上獨特的鹽和許多發子彈。這些算法傾向於以多種語言和框架實現眾所周知的實現。如果您碰巧找到了一個著名的經過測試的庫,其中除了鹽和鍵拉伸之外還包含胡椒,可能值得您花些時間使用,但是額外的好處通常會超過性能成本。
背景:您應該使用慢速密碼哈希。 (即bcrypt)“慢”是指在計算上很昂貴,需要花費100毫秒以上的時間(在您的硬件上)使用DoS保護* sups來測試單個密碼。如果散列被盜,這將增加通過蠻力查找密碼所需的處理能力(在攻擊者硬件上)。
每用戶唯一鹽是極力推薦的。 (對於bcrypt,它是自動生成的)Salt應該是高度 unique (即長&隨機的),但不是秘密。使用唯一的鹽意味著攻擊者必須為每個用戶運行單獨的蠻力作業 。
如果沒有“鹽”,攻擊者可以立即使用彩虹表,根本沒有蠻力。
如果僅使用“共享鹽”,那麼攻擊者可能會用單個蠻力破解所有用戶的密碼強迫喬布。 (不如彩虹表快,但比每個單獨的蠻力作業要容易得多)
答案:如果您要“不存儲”鹽(如您的教授所建議的,“用強力在運行時進行哈希處理”)
,這將完全違反 Salt的目的,嚴重削弱了Slow hash的優勢。那是您教授的主要設計錯誤。基本上,他是推行自己的密碼存儲方案,在該方案中,他應該使用經過嚴格審查的 bcrypt算法(或 scrypt或 PBKDF2)原定使用的地方。
*正如 @Navin所說,這可能是潛在的DoS攻擊媒介。一種解決方案是限制每個IP和每個用戶名每小時的嘗試次數。您還可以將散列的“慢度”降低到僅10ms。從“被竊取的散列”的角度來看,這不及100ms,但仍然比“微秒”更好。 sub>
您的教授是不正確的。加鹽的目的是增加散列密碼的熵,以防止對其進行任何預計算攻擊,並防止來自不同用戶的相同密碼具有相同的散列值。
能夠嘗試所有可能的鹽值意味著鹽中的熵必須非常低,這意味著可以通過彩虹表進行預計算。
您可以通過這種方式使用鹽。這將是一種哈希拉伸過程。通常,您通過重複執行數千次算法來擴展哈希,這會使攻擊者和用戶的速度降低1000倍,但用戶通常不介意這種速度降低。以這種方式使用鹽會產生哈希擴展算法的效果,因為必須對許多未知的哈希重複該算法。
但是,這是一種非常不尋常的方法。傳統的加鹽方法可以使鹽達到更好的效果(使鹽變得沒有人可以預先計算出密碼表)。傳統的進行哈希擴展的方法做的哈希擴展應該做的要好得多(這樣做使攻擊者需要更長的時間來計算密碼)。以這種方式使用鹽有點像將它們兩者融合在一起。結果有點類似,但較醜陋的技術混搭,更簡潔的方法在兩種解決方案上都遠。
我不是從蠻橫的角度考慮鹽,而是從說不可能通過查看密碼來告訴任何有關密碼的信息,包括密碼與其他密碼的關係。如果系統不加鹽,則查看兩個用戶的哈希密碼將表明他們的真實密碼是否匹配。如果系統僅使用用戶名進行鹽醃,而沒有使用隨機,特定時間或特定於系統的鹽,那麼在使用相同方法的兩台計算機上查看用戶的哈希密碼將表明兩台計算機上的用戶密碼是否匹配。如果系統使用系統ID和用戶名進行了加鹽處理,但沒有隨機性或特定於時間的設置,則可以由同一用戶訪問兩個不同密碼哈希的人可以判斷關聯的密碼是否匹配。
隨機加鹽是為了使即使使用相同密碼的兩個哈希都不會匹配,即使它們涉及同一系統上的同一用戶。如果登錄嘗試強行使用鹽,雖然可以在不存儲鹽的情況下達到類似的效果,但這種方法將限製鹽的實際使用長度,從而增加在兩種情況下使用密碼的可能性。相同的鹽,因此可以識別為匹配鹽。
加鹽有什麼作用?攻擊者已經預先計算了密碼哈希值的數據庫,包括普通密碼和非普通密碼。如果他們捕獲了您的數據庫並為每個用戶提供了密碼的哈希值,則很容易對照這些值檢查哈希值而無需添加鹽。
使用隨機鹽和密碼一起存儲的鹽,此瘋狂快速方法不再可行。但是,如果攻擊者既有鹽又有哈希,那麼仍然可以對弱密碼使用字典攻擊,對短密碼使用暴力破解。攻擊者所需要做的就是使用鹽,然後通過字典或蠻力攻擊嘗試使用不同的密碼。
現在,讓我們說說更改密碼時,您可以使用隨機的12位值對它進行散列不能和鹽一起儲存。然後,每次您檢查密碼時,都必須嘗試所有4096個值。在我的計算機上,這大約需要3.5毫秒,因此每秒可以檢查284個密碼。有人登錄時,服務器上的CPU使用率要高一些,但是對於嘗試字典或蠻力攻擊的人來說,即使他們有哈希值和鹽,您的工作也變得更加困難。
不存儲鹽的受控位數似乎有一些好處,該鹽是獨立配置的,並且與鹽的大小無關。
假設我們有32位鹽。我們可以選擇僅存儲22位,並在進行身份驗證時對其餘10位進行蠻力測試。這樣做的效果似乎是將更多回合添加到哈希函數中。合法身份認證的影響並不多,但是足以增加暴力破解的難度。
明年,計算機將變得更快。因此,我們瀏覽了密碼數據庫,並從每種鹽中剔除了一點:現在我們只存儲21位,並且必須通過11蠻力。
這就像我們將哈希強度加倍一樣,但是沒有替換算法的中斷以及使用戶重新哈希密碼(這取決於常規的密碼到期策略)。
這種“漸進式鹽丟棄”方法可以延長哈希函數的使用壽命。
但是,這些方法將合法身份驗證和蠻力攻擊減慢了相等的速度,因此充其量只能提供較小的安全層。我們的重點應該放在改進上,這些改進只會給合法使用增加恆定的額外時間,同時會增加破解難度。當然,具有此屬性的改進是增加了密碼短語中的熵!密碼中每增加一點熵,都會給合法用戶增加一定的成本,但會使暴力破解的工作量增加一倍。長度為N的密碼使用O(N)進行哈希(和鍵入),但使用O(2 ** N)進行暴力破解。在密碼中添加12位熵會掩蓋12位鹽。
在野外,我們有一個users表。用戶表通常是
ID |用戶名|鹽|加密密碼| horridly_insecure_reset_key ================================================= ======================== 1 | user1 | foo | 09b6d39aa22fcb8698687e1af09a3af9 | NULL2 | user2 |酒吧6c07c60f4b02c644ea1037575eb40005 | NULL3 | user3 | baz | 09b6d39aa22fcb8698687e1af09a3af9 |重置
然後,身份驗證方法將類似於
def authenticate(用戶,密碼)u = User.find(user:user)返回u。 crypto_password == crypto(password + u.salt)end
通過為每個用戶加鹽,它可以確保即使知道user1的密碼,您也無法弄清楚user2的密碼或沒有鹽的用戶3。
您還可以通過設置一組加密密碼並嘗試一些加密密碼來確保您不會發現問題。
本質上,通過這種方式,每次針對用戶必須從頭開始。
即使攻擊者擁有用戶和鹽的列表,他們仍然需要對每個用戶進行破解,以查看他們是否具有密碼匹配項。如果您有一大堆鹽或一種鹽,我可以知道user1的密碼是password,然後只需找到所有匹配的加密密碼即可。因此,這種方式至少會使它們的速度降低一點。
現在,當我們查看鹽時,我們希望減少鹽的重複使用。兩種相同的鹽將使攻擊者更容易使用。如果兩個人共享相同的密碼和相同的密碼,則破壞一個用戶將破壞另一個用戶。
所以可以說我們只使用這三種鹽。我們有3000個用戶。也就是說,有1000人食用相同的鹽分。如果其中有1%的密碼為“ password”,那麼這些人可以同時被全部破解。一次有10個帳戶被黑客入侵。因為我們知道這三種鹽。這是一次非常容易的工作,一次可以讓30個人受到攻擊。
現在,如果每種鹽都是唯一的。而且我們知道user1的密碼是password,這對您沒有任何好處。您仍然只破解了1個用戶。您仍然必須為所有其他2999個用戶執行“密碼+鹽=加密密碼”。
一個非常重要的說明。
默默無聞的安全性不是安全性。這並不意味著您應該在Google上發布用戶表,因為這很愚蠢。但是,在評估安全性時,您應該假設攻擊者擁有一切。您不能說:“但是他們不知道應用程序鹽,因為他們沒有源代碼”。因為他們可以。並不是說放棄您的鹽分,而是意味著它不是真正的安全性。假設他們具有用戶名和密碼,然後嘗試使他們更難於獲取密碼。
重要提示
此處使用的代碼和表大約是實際使用的9000倍。密碼未加密,鹽太短,方法有點簡單,簡而言之,在生產中做這樣的事情並不應該被認為是安全的。我選擇這些原因僅僅是為了演示,而不是因為它們是安全的。