最近有朋友在使勁研究如何不使用 HTTPS 的狀況下保護用戶密碼安全。暫且不說研究過程,但結論是要保障安全必須後端參與,使用非對稱加密算法 —— 如此一來,不如直接用 HTTPS 更簡單便捷有保障。使用免費 SSL 證書,一年一換,運維稍微麻煩一點,訪問稍微慢一點(證書認證過程好像會慢一些),但至少是專業的,比本身研究的沒通過大量檢驗的算法靠譜多了。前端
假設已經作過必要的安全防範,目前惟一須要解決的問題是保障用戶密碼在 HTTP 的明文傳輸過程當中不被竊取。爲達此目的,研究過程以下:算法
若是說,密碼在明文傳輸過程當中存在風險,最直接的解決辦法是讓密碼再也不是原來的樣子。使用一個 KEY
來加密密碼,再將加密後的結果傳輸到後臺,由後臺解密使用。數據庫
看起來確實起做用,若是竊取到加密後的密碼數據,沒有 KEY
是不能解密出來的。然而,KEY
要用於前端加密,就必定會存在於前端的某個地方,而前端的全部資源都是用戶能夠獲取並分析的,甚至可使用瀏覽器的開發者工具經過各類調試手段來分析獲取。因此 KEY
自己並不能安全保存,安全性被打破。segmentfault
此外,若是 secure_data
在傳輸過程被竊取,是能夠重複使用的(由於 KEY
不變,加密結果就不會變),這也是一個不安全因素。後端
結論 📚使用對稱加密算法來加密密碼的方式不能保證密鑰安全,也不能保證用戶密碼安全,更不能保護註冊/登陸過程安全。瀏覽器
使用對稱加密,在密文和密鑰都被竊取的時候,能夠解出密碼原文,對用戶在其餘系統中(可能使用了相同密碼)形成威脅。爲此,咱們可使用不可逆的 HASH 算法來處理密碼,只要先後端計算方式相同,不須要解密出密碼原文,直接使用 HASH 結果就行。緩存
用戶註冊時,假設咱們有原密碼 my_password
,使用 MD5 計算後是 a865a7e0ddbf35fa6f6a232e0893bea4
。這個 HASH 送到後端以後,後端是不能從 HASH 反算出原密碼的,因此後端只能直接保存這個 HASH。安全
那麼驗證的時候,一樣將原密碼計算成 HASH a865a7e0ddbf35fa6f6a232e0893bea4
,傳輸到後端,後端拿它和保存的數據進行對比,相同則驗證經過。服務器
有問題嗎?固然有,你看 ——運維
使用 Hash 的過程
不使用 HASH 的過程
從傳輸過程開始,Hash 前的過程和 Hash 後的過程並無區別。對於偷竊者來講,無所謂是拿到的 my_password
仍是 a865a7...
,只要把它送到後端,就能成功登陸。
因此這種作法並不能保護用戶登陸!
不過密碼是採用 Hash 計算過的,是否是能保護用戶密碼不會竊取用於嘗試登陸其餘系統呢?也不能!
一些常見的密碼,好比 123456
採用 MD5 計算後是 e10adc3949ba59abbe56e057f20f883e
,拿這個 Hash 上百度就能查出來原密碼是 123456
。固然,專業人士會有專業的工具,也就是彩虹表(什麼是彩虹表?查查唄!),數以 TB 計的數據,可能大部分密碼都查得出來吧。
結論 📚從前端對密碼進行單純的 HASH 算法,起不到任何保護做用。
其實從後端對密碼進行單純的 HASH 加密也只能起到很弱的保護做用,幾近裸奔。
HMAC 比單純的 HASH 算法,要多一個密鑰因素,能夠認爲是加密的 HASH。使用 HMAC 能夠有效的阻礙彩虹表破解。所以使用 HMAC 保護用戶密碼原文。可是,若是傳輸的是 HMAC 計算結果,和前面的討論同理,並不能保護登陸。
但使用 HMAC 和單純的 HASH 又有那麼一點不一樣。假設咱們已經經過其餘方式進行安全的註冊,後端已經保存了用戶密碼 my_password
,來看看下面這個登陸過程:
攻擊者只須要竊取 hash_result
便可仿冒登陸,而 hmac_result
在傳輸過程當中能夠輕鬆竊取。
此外,還有一個不安全點:固化在腳本中的 secure_key
是能夠從拉到客戶的腳本資源中分析出來的。
結論 📚使用固定 secure key 的 HMAC 算法並不能保障登陸安全,只能起到保密用戶密碼原文的做用。可是,因爲
secure_key
很容易被拿到,因此對密碼原文的保護也相對較弱。
繼續尋找解決辦法,咱們能夠想到一個改進方案:若是知足下面兩個條件,上面遇到的問題彷佛就能解決:
secure_key
並非固定在腳本中,而是動態產生的,就能夠解決從腳本分析得到 secure_key
的問題;secure_key
使用 1 次後當即失效,那麼 hmac_result
就不能用於再一次登陸,能夠解決 hmac_result
被竊取複用的問題。動態 secure_key
看起來是個不錯的辦法,可是它應該在哪裏動態產生呢?
若是在前端動態產生,就必須通知後端,傳輸的數據須要包含 secure_key
和 hmac_result
兩部分。他們都能被竊取使用。這種狀態下若是要保證 secure_key
只能使用一次,就必需要後端緩存全部用過的 secure_key
備查 —— 顯然這會極大的增長後端負擔。所以,不能夠由前端來產生動態安全碼。
用後端產生動態安全碼以後能夠當即緩存起來,同時傳輸給前端(這個過程能夠前端發起請求)。前端按上述步驟對用戶密碼進行加密,將數據送回後端。後端檢查 secure_key
在緩存中,取出來計算用於驗證的 hmac_result
,同時從緩存中刪除 secure_key
;若是 secure_key
不在緩存中,直接拒絕驗證。
引入動態 secure_key
解決了登陸期間驗證用戶密碼的問題。
雖然數據在傳輸過程當中仍然能被竊取,可是被竊取的數據不能重複使用,也不易破解出密碼原文(可花長時間暴力破解),因此這個方案是初步可行的 —— 但要注意,它可能會受中到中間人攻擊。
此外,該方案是不完整的,由於它只能解決驗證密碼(登陸)的問題,不能解決保存密碼(註冊)的問題 —— 注意到後端是直接從數據庫加載的 my_password
,這意味着在註冊時須要傳入密碼原文或者可解密出密碼原文的密文 —— 這在以前的研究中都還沒找到辦法。
結論 📚後端產生一次性使用的動態
secure_key
能夠保障登陸安全,但不能解決註冊安全。並且該方案須要注意防禦中間人攻擊。注意:須要後端參與
到目前爲止,咱們總算找到一個前端登陸勉強可用的安全方案。接下來還要研究用戶註冊時該怎麼辦。
註冊時須要傳輸可解密的密文,並且在前端不能找到可用於解密的密鑰 —— 這個場景很是符合非對稱加密的應用場景 —— 前端使用公鑰加密,後端使用私鑰解密,問題就能獲得完美解決:
結論 📚使用非對稱加密算法,能夠保護用戶密碼安全,也能夠保護登陸過程安全。可是要注意中間人攻擊。
注意:須要後端參與
到此爲止,咱們已經很是接近 HTTPS 了。HTTPS 主要就是採用的非對稱加密算法來保證數據傳輸安全。爲了防止中間人攻擊還引入了公信機構(受信任的證書中心)。可是,這個安全過程的參與方,包括 HTTPS 使用的安全協議(SSL 和 TSL 等)、服務器、公信機構、用戶本身等,均可能成爲整個安全過程的短板。
做爲專業保障 HTTP 傳輸安全的 HTTPS 協議都隨時在曝漏洞,請問,你又哪裏來的信心憑一已之力用本身的安全算法實現來代替 HTTPS?若是沒有足夠的能力,仍是安心用 HTTPS 吧!
請關注公衆號邊城客棧⇗
看完了先別走,點個贊 ⇓ 啊,讚揚 ⇘ 就更好啦!