和小伙伴們討論一個有爭議的話題:
有的人覺得密碼加密直接在服務端進行就可以了,沒必要在客戶端做;當然也有人覺得可以在客戶端進行密碼加密,降低服務器的壓力。
你要問松哥項目中是怎么做的,我會告訴你我們在客戶端就對密碼加密了。
為什么這么做呢?
我來和大家聊聊我們是怎么考慮的。
一、燙手山芋
首先我們有一個共識,就是明文密碼是一個燙手山芋,是一個定時炸彈,應該盡早處理。
把這樣一個炸彈從前端運到后端再進行加密處理,似乎并非一個好的辦法。應該盡早對炸彈進行處理,然后再進行運輸。
那么在客戶端就對密碼進行加密的目的是什么?防止密碼在傳輸過程中泄露嗎?
顯然不是!
對于重放攻擊來說,人家壓根不 care 你是否在客戶端加密密碼,對于重放攻擊來說,密碼是否在客戶端進行加密,問題都不大。
什么是重放攻擊? 重放攻擊(Replay Attack)是一種網(wǎng)絡安全攻擊,攻擊者通過截獲并重新發(fā)送之前捕獲的數(shù)據(jù)包,以實現(xiàn)對系統(tǒng)的欺詐或破壞。這種攻擊通常發(fā)生在沒有正確實現(xiàn)消息認證和完整性保護的系統(tǒng)中。 一般來說,重放攻擊有三個特點:
-
無需破解加密:攻擊者不需要知道加密算法或密鑰,只需復制和重放數(shù)據(jù)包。
-
依賴于協(xié)議的缺陷:如果協(xié)議沒有設計好,沒有實現(xiàn)時間戳、序列號或一次性令牌等機制,就容易被重放攻擊。
-
可重復性:攻擊者可以多次重放相同的數(shù)據(jù)包,嘗試獲取相同的結果。
一般來說,解決重放攻擊比較有效并且省事的辦法就是上 HTTPS。
客戶端對密碼進行加密的目的是為了防止明文密碼在到達后端之后被濫用。這是最主要的目的。
為了增加破解成本,在前端進行加密的時候,可以使用慢 hash 函數(shù)。
二、什么是慢 hash
慢哈希函數(shù)(Slow Hash Function)是一種密碼學上的哈希函數(shù),它被設計成故意減慢處理速度,以增加破解的難度。
這種函數(shù)通常用于密碼存儲、密鑰派生和某些加密算法中,目的是提供額外的安全層,防止暴力破解攻擊。
一般來說,慢哈希函數(shù)主要有下面一些特點:
-
計算成本高:故意設計成需要更多計算資源(CPU 時間或內(nèi)存),使得暴力破解這種方式變得不切實際。
-
內(nèi)存密集型:許多慢哈希函數(shù)需要大量的內(nèi)存,這增加了并行處理的難度,因為每個哈希計算實例都需要獨立的內(nèi)存空間。
-
抵抗暴力破解:由于計算成本高,慢哈希函數(shù)使得暴力破解(嘗試所有可能的密碼直到找到匹配)變得非常困難。
-
鹽值(Salt):慢哈希函數(shù)通常與鹽值結合使用,鹽值是隨機生成的數(shù)據(jù),用于與密碼組合,確保即使兩個用戶使用相同的密碼,他們的哈希值也會不同。
-
密鑰延展(Key Stretching):通過多次迭代哈希過程,進一步增加破解難度。
常見的慢哈希函數(shù)主要有如下幾種,這幾種也是我們在 Spring Security 中比較常見的:
-
PBKDF2(Password-Based Key Derivation Function 2):使用 HMAC 作為偽隨機函數(shù),可以配置迭代次數(shù)來增加計算時間。
-
BCrypt:專為密碼存儲設計,包含鹽值和多輪哈希計算。
-
scrypt:設計用于加密貨幣和密碼存儲,特別強調(diào)內(nèi)存密集型,以抵抗 GPU 和 ASIC 硬件加速的暴力破解。
-
Argon2:是當前最推薦使用的慢哈希函數(shù)之一,它贏得了密碼哈希競賽(Password Hashing Competition),并被設計為抵抗各種類型的攻擊,包括定制硬件攻擊。
以 BCrypt 為例,如果我們控制 BCrypt 的執(zhí)行時間大概是 0.1 秒完成一次哈希計算的話,按照 1 秒生成 10 個哈希值的速度,算完所有的 10 位大小寫字母和數(shù)字組成的弱密碼大概需要 P(62,10)/(3600×24×365x10)=1,237,204,169 年時間。
三、一次用戶注冊
了解了慢哈希之后,我們來看一次完整的用戶注冊應該是什么樣子的。
首先,用戶在客戶端輸入明文密碼 123。
接下來,客戶端對密碼進行加密,可以使用 SHA256 散列函數(shù),如果想要謹慎一些,也可以使用用戶名等信息作為鹽,以防止彩虹表的攻擊。
現(xiàn)在就可以由客戶端發(fā)送密碼到服務端了。
服務端收到客戶端發(fā)來的消息之后,在服務端眼里可以將客戶端發(fā)來的密碼就當成明文,按照明文的處理流程進行加密并存儲,這塊松哥在 Spring Security 中和大家講過多次了,不贅述。
這就是用戶注冊的流程。
將來用戶登錄其實也是一樣的。
用戶在客戶端輸入密碼之后,現(xiàn)在客戶端進行加密,然后再上傳到服務端,服務端再按照我們在 Spring Security 中講的方式進行處理就可以了。