離開後端說前端加密都是空談

邊城發表於2020-05-29

最近有朋友在使勁研究如何不使用 HTTPS 的情況下保護使用者密碼安全。暫且不說研究過程,但結論是要保障安全必須後端參與,使用非對稱加密演算法 —— 如此一來,不如直接用 HTTPS 更簡單便捷有保障。使用免費 SSL 證書,一年一換,運維稍微麻煩一點,訪問稍微慢一點(證書認證過程好像會慢一些),但至少是專業的,比自己研究的沒經過大量檢驗的演算法靠譜多了。

假設已經做過必要的安全防範,目前唯一需要解決的問題是保障使用者密碼在 HTTP 的明文傳輸過程中不被竊取。為達此目的,研究過程如下:

對稱演算法加密密碼

如果說,密碼在明文傳輸過程中存在風險,最直接的解決辦法是讓密碼不再是原來的樣子。使用一個 KEY 來加密密碼,再將加密後的結果傳輸到後臺,由後臺解密使用。

image.png

看起來確實起作用,如果竊取到加密後的密碼資料,沒有 KEY 是不能解密出來的。然而KEY 要用於前端加密,就一定會存在於前端的某個地方,而前端的所有資源都是使用者可以獲取並分析的,甚至可以使用瀏覽器的開發者工具通過各種除錯手段來分析獲取。所以 KEY 本身並不能安全儲存,安全性被打破。

此外,如果 secure_data 在傳輸過程被竊取,是可以重複使用的(因為 KEY 不變,加密結果就不會變),這也是一個不安全因素。


結論 ?

使用對稱加密演算法來加密密碼的方式不能保證金鑰安全,也不能保證使用者密碼安全,更不能保護註冊/登入過程安全。

對密碼進行單純的 HASH

使用對稱加密,在密文和金鑰都被竊取的時候,可以解出密碼原文,對使用者在其他系統中(可能使用了相同密碼)造成威脅。為此,我們可以使用不可逆的 HASH 演算法來處理密碼,只要前後端計算方式相同,不需要解密出密碼原文,直接使用 HASH 結果就行。

使用者註冊時,假設我們有原密碼 my_password,使用 MD5 計算後是 a865a7e0ddbf35fa6f6a232e0893bea4。這個 HASH 送到後端之後,後端是不能從 HASH 反算出原密碼的,所以後端只能直接儲存這個 HASH。

那麼驗證的時候,同樣將原密碼計算成 HASH a865a7e0ddbf35fa6f6a232e0893bea4,傳輸到後端,後端拿它和儲存的資料進行對比,相同則驗證通過。

有問題嗎?當然有,你看 ——

使用 Hash 的過程

image.png

不使用 HASH 的過程

image.png

從傳輸過程開始,Hash 前的過程和 Hash 後的過程並沒有區別。對於偷竊者來說,無所謂是拿到的 my_password 還是 a865a7...,只要把它送到後端,就能成功登入。

所以這種做法並不能保護使用者登入!

不過密碼是採用 Hash 計算過的,是不是能保護使用者密碼不會竊取用於嘗試登入其他系統呢?也不能!

一些常見的密碼,比如 123456 採用 MD5 計算後是 e10adc3949ba59abbe56e057f20f883e,拿這個 Hash 上百度就能查出來原密碼是 123456。當然,專業人士會有專業的工具,也就是彩虹表(什麼是彩虹表?查查唄!),數以 TB 計的資料,可能大部分密碼都查得出來吧。


結論 ?

從前端對密碼進行單純的 HASH 演算法,起不到任何保護作用。

其實從後端對密碼進行單純的 HASH 加密也只能起到很弱的保護作用,幾近裸奔。

引入金鑰,使用 HMAC

HMAC 比單純的 HASH 演算法,要多一個金鑰因素,可以認為是加密的 HASH。使用 HMAC 可以有效的阻礙彩虹表破解。因此使用 HMAC 保護使用者密碼原文。但是,如果傳輸的是 HMAC 計算結果,和前面的討論同理,並不能保護登入。

但使用 HMAC 和單純的 HASH 又有那麼一點不同。假設我們已經通過其他方式進行安全的註冊,後端已經儲存了使用者密碼 my_password,來看看下面這個登入過程:

image.png

攻擊者只需要竊取 hash_result 即可仿冒登入,而 hmac_result 在傳輸過程中可以輕鬆竊取。

此外,還有一個不安全點:固化在指令碼中的 secure_key 是可以從拉到客戶的指令碼資源中分析出來的。


結論 ?

使用固定 secure key 的 HMAC 演算法並不能保障登入安全,只能起到保密使用者密碼原文的作用。但是,由於 secure_key 很容易被拿到,所以對密碼原文的保護也相對較弱。

引入動態安全碼 (secure key)

繼續尋找解決辦法,我們可以想到一個改進方案:如果滿足下面兩個條件,上面遇到的問題似乎就能解決:

  • secure_key 並不是固定在指令碼中,而是動態產生的,就可以解決從指令碼分析獲得 secure_key 的問題;
  • 這個 secure_key 使用 1 次後立即失效,那麼 hmac_result 就不能用於再一次登入,可以解決 hmac_result 被竊取複用的問題。

動態 secure_key 看起來是個不錯的辦法,但是它應該在哪裡動態產生呢?

如果在前端動態產生,就必須通知後端,傳輸的資料需要包含 secure_keyhmac_result 兩部分。他們都能被竊取使用。這種狀態下如果要保證 secure_key 只能使用一次,就必須要後端快取所有用過的 secure_key 備查 —— 顯然這會極大的增加後端負擔。因此,不可以由前端來產生動態安全碼。

image.png

用後端產生動態安全碼之後可以立即快取起來,同時傳輸給前端(這個過程可以前端發起請求)。前端按上述步驟對使用者密碼進行加密,將資料送回後端。後端檢查 secure_key 在快取中,取出來計算用於驗證的 hmac_result,同時從快取中刪除 secure_key;如果 secure_key 不在快取中,直接拒絕驗證。

image.png

引入動態 secure_key 解決了登入期間驗證使用者密碼的問題。

雖然資料在傳輸過程中仍然能被竊取,但是被竊取的資料不能重複使用,也不易破解出密碼原文(可花長時間暴力破解),所以這個方案是初步可行的 —— 但要注意,它可能會受中到中間人攻擊。

此外,該方案是不完整的,因為它只能解決驗證密碼(登入)的問題,不能解決儲存密碼(註冊)的問題 —— 注意到後端是直接從資料庫載入的 my_password,這意味著在註冊時需要傳入密碼原文或者可解密出密碼原文的密文 —— 這在之前的研究中都還沒找到辦法。


結論 ?

後端產生一次性使用的動態 secure_key 可以保障登入安全,但不能解決註冊安全。而且該方案需要注意防護中間人攻擊

注意:需要後端參與

使用非對稱加密

到目前為止,我們總算找到一個前端登入勉強可用的安全方案。接下來還要研究使用者註冊時該怎麼辦。

註冊時需要傳輸可解密的密文,而且在前端不能找到可用於解密的金鑰 —— 這個場景非常符合非對稱加密的應用場景 —— 前端使用公鑰加密,後端使用私鑰解密,問題就能得到完美解決:

image.png


結論 ?

使用非對稱加密演算法,可以保護使用者密碼安全,也可以保護登入過程安全。但是要注意中間人攻擊

注意:需要後端參與

使用 HTTPS

到此為止,我們已經非常接近 HTTPS 了。HTTPS 主要就是採用的非對稱加密演算法來保證資料傳輸安全。為了防止中間人攻擊還引入了公信機構(受信任的證書中心)。但是,這個安全過程的參與方,包括 HTTPS 使用的安全協議(SSL 和 TSL 等)、伺服器、公信機構、使用者自己等,都可能成為整個安全過程的短板。

作為專業保障 HTTP 傳輸安全的 HTTPS 協議都隨時在曝漏洞,請問,你又哪裡來的信心憑一已之力用自己的安全演算法實現來代替 HTTPS?如果沒有足夠的能力,還是安心用 HTTPS 吧!


邊城客棧

請關注公眾號邊城客棧

看完了先別走,點個贊 ⇓ 啊,讚賞 ⇘ 就更好啦!

相關文章