前端安全是Web安全的一部分,常見的安全問題會有XSS、CSRF、SQL注入等,然而這些已經在程師界獲得了至關高的重視而且有了很成熟的解決方案。 因此咱們今天只談前端「加密」,一個部分人認爲沒有意義的工做。 有爭議的事情老是那麼因崔斯汀,接下來就讓咱們談談前端傳輸中的數據「加密」 。前端
前端傳輸的數據咱們應該用什麼算法加密,如何組織整個加密過程呢? 通常有幾種作法:算法
JavaScript 加密後傳輸數據庫
瀏覽器插件內進行加密傳輸後端
Https 傳輸瀏覽器
在這裏其實 HTTPS 是終極解決方案,因此文章對於仍在使用 HTTP 建站的小夥伴更有幫助。本文中將討論第一種方法,也就是使用 JavaScript "加密"。使用雙引號是由於這裏面分爲兩種手段,一是使用數據摘要進行消息雜湊,二是使用非對稱加密算法對明文進行加密。安全
嚴格意義來講第一種手段並不是加密,而是一種信息摘要的應用,爲了闡述方便下文通通使用加密一詞。在進行下文以前,須要簡單的介紹幾個概念:服務器
上圖中咱們能夠明顯看到哈希和加密是兩個不一樣的東西,主要有兩點不一樣:網絡
哈希算法一般用於數據摘要,生成相同長度的文本。而加密算法生成的密文長度與明文長度有關。框架
哈希算法是不可逆的,而加密算法是可逆的。性能
在加密算法中又分爲對稱加密(symmetric encryption)和非對稱加密(asymmetric encryption)。非對稱加密算法中,加密密鑰和解密密鑰是不一樣的,分爲私鑰和公鑰,咱們熟知的 RSA 就是一種非對稱加密算法。而對稱加密中,加密和解密都是用同一個密鑰,如 AES / DES。從性能上來講,非對稱加密相對於對稱加密要慢不少。在 HTTPS 中,認證過程使用了非對稱加密算法,非認證過程當中使用了對稱加密算法。
在 HTTP 協議下,數據是明文傳輸,傳輸過程當中網絡嗅探可直接獲取其中的數據。 如用戶的密碼和信用卡相關的資料,一旦被中間人獲取,會給用戶帶來極大的安全隱患。另外一方面在非加密的傳輸過程當中,攻擊者可更改數據或插入惡意的代碼等。HTTPS 的誕生就是爲了解決中間人攻擊的問題,但現在 HTTPS 的使用狀況在國內並不樂觀,基本是由於成本或者性能的考量。
Q:那麼問題來了,若是仍然使用 HTTP 協議怎麼樣必定程度保證用戶的數據安全?
A:前端加密,即在數據發送前將數據進行哈希或使用公鑰加密。若是數據被中間人獲取,拿到的則再也不是明文。
設想在現在公共 WIFI 流行的今天,一旦某一個 AP 的流量被攻擊者劫持,若是密碼和用戶名都是明文,那麼攻擊者將垂手可得的使用這些資料進行 Replay 登陸。更糟糕的是不少用戶在不一樣的網站使用相同的帳號信息,用戶的隱私蕩然無存。做爲網站服務提供者,網站設計和開發人員應該爲用戶提供相對安全的服務,這是一種責任也是一種情懷。
另外若是前端使用哈希算法,不只能夠幫助後端分擔部分計算壓力,還能夠增長撞庫成本。具體的討論將在下文繼續。
前面說過使用 JavaScript 加密有兩種方式,一是使用哈希進行信息摘要,一種是使用非對稱加密。在國內的知名站點中,這兩種方式都有人使用。接下來咱們分別來深刻了解加密過程,探討下如何應對不一樣的場景。
爲了不傳輸過程當中的明文風險,前端能夠在發送敏感數據前對其加密,如密碼。因爲哈希算法的不可逆性,中間人沒法從截取的數據中得知用戶的密碼信息。可是這裏有一個問題,攻擊者仍然可使用拿到的哈希值進行直接登陸。使用前端加密如何避免中間人重放攻擊?帶着這個問題,咱們回顧下後臺如何驗證用戶。
不少站點後臺對於用戶密碼處理也是用哈希算法,一方面由於不須要將密文解密成明文來比對密碼,另外一方面是一旦加密算法和密鑰泄露,那麼整個用戶資料庫就至關於明文存儲了。若是前端傳過來的是明文,那麼在註冊時將其哈希,存入數據庫。登陸時,將密碼哈希和數據庫對應的數據比對,若一致則說明密碼正確。
若是咱們使用 Salt 是否能夠解決問題?若是前端傳過來的是加了 salt 的哈希值,咱們須要後端存有同一份 salt ,用其和數據庫的加密密碼哈希,而後與前端傳過來的哈希值比對。兩個過程的對比見下圖:
很容易知道,若是 Salt 不是每次登錄不一樣,那麼攻擊者仍可使用加密後的密碼進行直接登錄,因此必須使用動態 Salt。動態 Salt 有不少方法,能夠是動態的 Token,也能夠直接使用現成的驗證碼。 這當中使用驗證碼是對後臺系統改動較小且效果不錯的,咱們來看看怎麼樣結合驗證碼進行前端加密。
前端先將密碼哈希,而後和用戶輸入的驗證碼進行哈希,獲得的結果做爲密碼字段發送給服務器。服務器先確認驗證碼正確,而後再進行密碼驗證,不然直接返回驗證碼錯誤信息。
這種實踐保證了密碼在傳輸過程當中的資料安全,即便攻擊者拿到了數據也沒法重放。圖形化驗證碼更是增長了難度。另外一方面該實踐大大增長了撞庫的成本。
前端加密必定程度保障了傳輸過程當中的資料安全,那麼會不會有對兩端(客戶端和服務器)有安全幫助呢? 有幫助,使用一些前端加密手段,能夠增長拖庫後的數據破解難度。可是以前介紹的驗證碼方法不具備這樣的功能,由於數據庫存的還是明文密碼哈希後的結果,那麼攻擊者能夠繞過前端加密,能夠直接暴力破解。
使用怎麼樣的前端加密方法能夠增長拖庫後的數據破解難度?從兩個方面分別去思考,一是下降破解速度,二是須要前端加密結果影響數據庫的數據存儲。數據被暴力破解出來的時間與哈希算法速度負相關。
咱們知道暴力破解便是使用相同的算法把經常使用的字符組跑一遍,若是結果相同那麼就猜中明文了。若是算法越快,便能更快的破解。例如 MD5 加密一次耗費1微秒,那麼攻擊者一秒鐘就能夠猜大約 100萬個詞組。因此爲了減慢破解速度,咱們須要增長破解的時間,一個直接的方法就是使用更慢的算法,咱們能夠把經常使用的MD5算法替換爲 bcrypt,PBKDF2 等慢算法。
對於須要前端加密結果影響數據庫的數據存儲,即爲後端加密把前端加密結果當作明文密碼,那麼存在庫裏的密碼即是前端哈希加上後端加密的結果。因爲慢的算法會增長服務器計算壓力,當咱們把一部分哈希工做拿到前端,即減慢了加密速度,減輕了服務器壓力,也順帶完成了前端加密的工做。
加密速度減慢必定程度會下降用戶體驗,這也是一部分站點未啓用 https 的緣由之一。可是由於咱們的前端加密只會用在不常使用的登陸和註冊上,因此不會影響網站總體的體驗。
綜上,咱們可使用更慢的算法,加之視前端哈希結果爲明文密碼,即可增長拖庫破解的成本。既然增長了破解的成本,撞庫的成本也一樣增長了。爲了不攻擊者先前使用先後端加密生成的新字典,咱們須要加鹽,並不按期更新鹽值。下圖文是使用過時 Salt 的方法描述:
前端加密使用按期刷新的 Salt,哈希後生成密文,再通過後端加密後即爲用於比對的密文。數據庫中的密碼哈希值跟着 Salt 進行變化,先後端須要有一套salt的更新機制。
回顧前端哈希的方法,解決了中間人攻擊重放、加大了拖庫破解的難度。雖然這些方法都不能徹底保證用戶安全,可是做爲站點服務者,應該視用戶爲上帝嘛。這些方法也不過就是幾行代碼的事,可是卻能必定程度的避免了用戶帳號被盜等風險。
上文中咱們討論了前端的哈希加密以及應用的場景。對於十足的安全控來講,這樣的措施對於有心的攻擊者基本沒有用。那麼咱們能夠採用更強的措施保障傳輸中的敏感數據安全。
以前有說過加密算法分爲對稱加密和非對稱加密,由於前端的透明性,使用JavaScript來進行對稱加密是不可能的了,那麼只剩下了非對稱加密這個選擇。通過筆者幾天的調研發現,某鵝某浪的部分登陸頁面採用非對稱加密對密碼加密。這些站點目前都仍是使用 http 協議,這樣的安全措施必定程度保證了用戶的密碼安全。
前端使用非對稱加密原理很簡單,先後端共用一套加密解密算法,前端使用公鑰對數據加密,後端使用私鑰將數據解密爲明文。中間攻擊人拿到密文,若是沒有私鑰的話是沒辦法破解的。
可能有人會指出加密算法一旦被破解,這一套安全措施就沒用了。何況 JavaScript 的生成安全隨機數仍是個問題,因此其實這是用不了 https 的權衡之計。在沒有 https 的狀況下,使用 JavaScript 非對稱加密或者 插件加密通信是比較好的替代方法,後者優於前者。
做爲一個前端開發者,咱們眼裏不該該只充斥各類框架,更不能被旁人一句沒有意義的話給擊退。任何解決方案都有其適用的範圍,世界上根本就沒有銀彈,安全問題亦是如此。因此根據實際的狀況採起符合本身的安全解決方案很重要,即便辦法不是 100% 有效,也不能放棄那 1% 能夠爲用戶保障安全的機會。