前端面試查漏補缺--(八) 前端加密

前言

本系列最開始是爲了本身面試準備的.後來發現整理愈來愈多,差很少有十二萬字符,最後決定仍是分享出來給你們.前端

爲了分享整理出來,花費了本身大量的時間,起碼是隻本身用的三倍時間.若是喜歡的話,歡迎收藏,關注我!謝謝!vue

文章連接

合集篇:

前端面試查漏補缺--Index篇(12萬字符合集) 包含目前已寫好的系列其餘十幾篇文章.後續新增值文章不會再在每篇添加連接,強烈建議議點贊,關注合集篇!!!!,謝謝!~面試

後續更新計劃

後續還會繼續添加設計模式,前端工程化,項目流程,部署,閉環,vue常考知識點 等內容.若是以爲內容不錯的話歡迎收藏,關注我!謝謝!算法

求一分內推

目前本人也在準備跳槽,但願各位大佬和HR小姐姐能夠內推一份靠譜的武漢 前端崗位!郵箱:bupabuku@foxmail.com.謝謝啦!~數據庫

前端加密的意義

這是一個繞不開的話題,確定有不少見解.但我看來:前端加密看起來有意義,但有時候看起來並無"意義". 但整體來看是有意義的,打個比喻:既然市面上大部分鎖均可以在20分鐘內撬開,那門上裝鎖是否還有意義?後端

有意義:
在 HTTP 協議下,數據是明文傳輸,傳輸過程當中網絡嗅探可直接獲取其中的數據。 如用戶的密碼和信用卡相關的資料,一旦被中間人獲取,會給用戶帶來極大的安全隱患。另外一方面在非加密的傳輸過程當中,攻擊者可更改數據或插入惡意的代碼等。那麼前端加密的意義: 即在數據發送前將數據進行哈希或使用公鑰加密。若是數據被中間人獲取,拿到的則再也不是明文。設計模式

固然還有其餘一些優勢:例如避免後端等打印日誌直接暴露明文密碼,還能夠避免明文撞庫等.前端工程化

沒有"意義": 前端加密,其實只能防君子不能防小人。 前端系統的控制權是徹底在用戶手裏的,也就是說,前端作什麼事情,用戶有徹底的控制權。即便前端加密不能夠防範中間人攻擊,包括HTTPS,由於中間仍是存在着各類代理,客戶端代理,服務端代理.是很難作到不被劫持的.跨域

這裏簡單說下:瀏覽器

  • 加密了也沒法解決重放的問題,你發給服務器端的雖然是加密後的數據,可是黑客攔截以後,把加密以後的數據重發一遍,依然是驗證經過的。直接監聽到你所謂的密文,而後用腳本發起一個http請求就能夠登陸上去了。 http在網絡上是明文傳輸的,代理和網關都可以看到全部的數據,在同一局域網內也能夠被嗅探到。加密也沒有提升什麼攻擊難度,由於攻擊者就不必去解密原始密碼,能登陸上去就表示目標已經實現了,因此,難度沒有提升。
  • 既然是加密,那麼加密用的密鑰和算法確定是保存在前端的,攻擊者經過查看源碼就能獲得算法和密鑰。除非你是經過作瀏覽器插件,將算法和密鑰封裝在插件中,而後加密的時候明文混淆上時間戳,這樣即便黑客攔截到了請求數據,進行重放過程時,也會很快失效。

總結一下:

  • 1,安全是先後端都須要作的事,不能前端加密了,後端就無論了.
  • 2,HTTPS仍是有必要的,只要正確使用了HTTPS鏈接和服務器端安全的哈希算法,密碼系統均可以是很安全的。

這裏我只是簡單梳理下,若是還有疑惑想深刻探(si)討(bi)的,能夠看下逼乎上的這篇文章

前端加密的幾種作法

• JavaScript 加密後傳輸(具體能夠參考後面的常見加密方法)

• 瀏覽器插件內進行加密傳輸 (這個用得不是不少,這裏暫不細究)

• Https 傳輸

加密算法

不一樣於哈希(後面會提到),加密(Encrypt)是將目標文本轉換成具備不一樣長度的、可逆的密文。也就是說加密算法是可逆的,並且其加密後生成的密文長度和明文自己的長度有關。因此若是被保護數據在之後須要被還原成明文,則須要使用加密。

在加密算法中又分爲對稱加密(symmetric encryption)和非對稱加密(asymmetric encryption)。

對稱加密

對稱加密採用了對稱密碼編碼技術,它的特色是文件加密和解密使用相同的密鑰加密.也就是加密和解密都是用同一個密鑰,這種方法在密碼學中叫作對稱加密算法.

對稱加密算法使用起來簡單快捷,密鑰較短,且破譯困難,除了數據加密標準(DES),另外一個對稱密鑰加密系統是國際數據加密算法(IDEA),它比DES的加密性好,並且對計算機功能要求也沒有那麼高.

常見的對稱加密算法有DES、3DES、Blowfish、IDEA、RC四、RC五、RC6和AES

注意: 由於前端的透明性,對於登陸密碼等敏感信息,就不要使用JavaScript來進行對稱加密. 由於別人能夠從前端獲得密匙後,能夠直接對信息進行解密!

非對稱加密

非對稱加密算法須要兩個密鑰:公鑰(publickey)和私鑰(privatekey)。 公鑰與私鑰是一對,若是用公鑰對數據進行加密,只有用對應的私鑰才能解密;若是用私鑰對數據進行加密,那麼只有用對應的公鑰才能解密。 由於加密和解密使用的是兩個不一樣的密鑰,因此這種算法叫做非對稱加密算法。

非對稱加密算法實現機密信息交換的基本過程是:甲方生成一對密鑰並將其中的一把做爲公鑰向其它方公開;獲得該公鑰的乙方使用該密鑰對機密信息進行加密後再發送給甲方;甲方再用本身保存的另外一把專用密鑰對加密後的信息進行解密。甲方只能用其專用密鑰解密由其公鑰加密後的任何信息。

常見的非對稱加密算法有:RSA、ECC(移動設備用)、Diffie-Hellman、El Gamal、DSA(數字簽名用)

哈希加密算法

哈希算法(Hash)

哈希(Hash)是將目標文本轉換成具備固定長度的字符串(或叫作消息摘要)。 當輸入發生改變時,產生的哈希值也是徹底不一樣的。從數學角度上講,一個哈希算法是一個多對一的映射關係,對於目標文本 T,算法 H 能夠將其惟一映射爲 R,而且對於全部的 T,R 具備相同的長度,因此 H 不存在逆映射,也就是說哈希算法是不可逆的。

基於哈希算法的特性,其適用於該場景:被保護數據僅僅用做比較驗證且不須要還原成明文形式。比較經常使用的哈希算法是 MD5 和 SHA1 。

咱們比較熟悉的使用哈希存儲數據的例子是:當咱們登陸某個已註冊網站時,在忘記密碼的狀況下須要重置密碼,此時網站會給你發一個隨機的密碼或者一個郵箱激活連接,而不是將以前的密碼發給你,這就是由於哈希算法是不可逆的。

須要注意的是:在 Web 應用中,在瀏覽器中使用哈希加密的同時也要在服務端上進行哈希加密。

服務端哈希加密緣由: 一方面由於不須要將密文解密成明文來比對密碼,另外一方面是一旦加密算法和密鑰泄露,那麼整個用戶資料庫就至關於明文存儲了。若是前端傳過來的是明文,那麼在註冊時將其哈希,存入數據庫。登陸時,將密碼哈希和數據庫對應的數據比對,若一致則說明密碼正確。

如今,對於簡單的哈希算法的攻擊方法主要有:尋找碰撞法和窮舉法。因此,爲了保證數據的安全,能夠在哈希算法的基礎上進一步的加密,常見的方法有:加鹽、慢哈希、密鑰哈希、XOR 等。

加鹽(Adding Salt)

加鹽加密是一種對系統登陸口令的加密方式,它實現的方式是將每個口令同一個叫作「鹽」(salt)的 n 位隨機數相關聯。

爲了方便理解:這裏引用這位同窗的文章進行說明:

使用salt加密,它的基本想法是這樣的:

  • 1.用戶註冊時,在密碼上撒一些鹽。生成一種味道,記住味道。
  • 2.用戶再次登錄時,在輸入的密碼上撒鹽,聞一聞,判斷是否和原來的味道相同,相同就讓你吃飯。

因爲驗證密碼時和最初散列密碼時使用相同的鹽值,因此salt的存儲在數據庫。而且這個值是由系統隨機產生的,而非硬編碼。這就保證了所要保護對象的機密性。

註冊時:

  • 1.用戶註冊,系統隨機產生salt值。
  • 2.將salt值和密碼鏈接起來,生產Hash值。
  • 3.將Hash值和salt值分別存儲在數據庫中。

登錄時:

  • 1.系統根據用戶名找到與之對應的密碼Hash。
  • 2.將用戶輸入密碼和salt值進行散列。
  • 3.判斷生成的Hash值是否和數據庫中Hash相同。

PS: 其實圖中的這種登陸也是不安全的. 緣由是後面要提到的鹽值複用

使用加鹽加密時須要注意如下兩點:

  • 短鹽值(Short Slat)

若是鹽值過短,攻擊者能夠預先製做針對全部可能的鹽值的查詢表。例如,若是鹽值只有三個 ASCII 字符,那麼只有 95x95x95=857,375 種可能性,加大了被攻擊的可能性。還有,不要使用可預測的鹽值,好比用戶名,由於針對某系統用戶名是惟一的且被常常用於其餘服務。

  • 鹽值複用(Salt Reuse)

在項目開發中,有時會遇到將鹽值寫死在程序裏或者只有第一次是隨機生成的,以後都會被重複使用,這種加鹽方法是不起做用的。以登陸密碼爲例,若是兩個用戶有相同的密碼,那麼他們就會有相同的哈希值,攻擊者就可使用反向查表法對每一個哈希值進行字典攻擊,使得該哈希值更容易被破解。

因此正確的加鹽方法以下:

(1)鹽值應該使用加密的安全僞隨機數生成器( Cryptographically Secure Pseudo-Random Number Generator,CSPRNG )產生,好比 C 語言的 rand() 函數,這樣生成的隨機數高度隨機、徹底不可預測;

(2)鹽值混入目標文本中,一塊兒使用標準的加密函數進行加密;

(3)鹽值要足夠長(經驗代表:鹽值至少要跟哈希函數的輸出同樣長)且永不重複;

(4)鹽值最好由服務端提供,前端取值使用。

慢哈希函數(Slow Hash Function)

顧名思義,慢哈希函數是將哈希函數變得很是慢,使得攻擊方法也變得很慢,慢到足以令攻擊者放棄,而每每由此帶來的延遲也不會引發用戶的注意。下降攻擊效率用到了密鑰擴展( key stretching)的技術,而密鑰擴展的實現使用了一種 CPU 密集型哈希函數( CPU-intensive hash function)。看起來有點暈~仍是關注下該函數怎麼用吧!

若是想在一個 Web 應用中使用密鑰擴展,則須要設定較低的迭代次數來下降額外的計算成本。咱們通常直接選擇使用標準的算法來完成,好比 PBKDF2 或 bcrypt 。PHP、斯坦福大學的 JavaScript 加密庫都包含了 PBKDF2 的實現,瀏覽器中則能夠考慮使用 JavaScript 完成,不然這部分工做應該由服務端進行計算。

密鑰哈希

密鑰哈希是將密鑰添加到哈希加密,這樣只有知道密鑰的人才能夠進行驗證。目前有兩種實現方式:使用 ASE 算法對哈希值加密、使用密鑰哈希算法 HMAC 將密鑰包含到哈希字符串中。爲了保證密鑰的安全,須要將其存儲在外部系統(好比一個物理上隔離的服務端)。

即便選擇了密鑰哈希,在其基礎上進行加鹽或者密鑰擴展處理也是頗有必要。目前密鑰哈希用於服務端比較多,例如來應對常見的 SQL 注入攻擊。

XOR

XOR 你們都不陌生,它指的是邏輯運算中的 「異或運算」。兩個值相同時,返回 false,不然返回 true,用來判斷兩個值是否不一樣。

JavaScript 語言的二進制運算,有一個專門的 XOR 運算符,寫做^。

1 ^ 1 // 0

0 ^ 0 // 0

1 ^ 0 // 1

0 ^ 1 // 1

複製代碼

XOR 運算有一個特性:若是對一個值連續作兩次 XOR,會返回這個值自己。這也是其能夠用於信息加密的根本。

message XOR key // cipherText

cipherText XOR key // message

複製代碼

目標文本 message,key 是密鑰,第一次執行 XOR 會獲得加密文本;在加密文本上再用 key 作一次 XOR 就會還原目標文本 message。爲了保證 XOR 的安全,須要知足如下兩點:

(1)key 的長度大於等於 message ;

(2)key 必須是一次性的,且每次都要隨機產生。

下面以登陸密碼加密爲例介紹下 XOR 的使用:

第一步:使用 MD5 算法,計算密碼的哈希;

const message = md5(password);

複製代碼

第二步:生成一個隨機 key 值;

第三步:進行 XOR 運算,求出加密後的 message。

function getXOR(message, key) 

const arr = [];

//假設 key 是32位的

for (let i = 0; i < 32; i++) {
  const  m = parseInt(message.substr(i, 1), 16);
  const k = parseInt(key.substr(i, 1), 16);
  arr.push((m ^ k).toString(16));
}

return arr.join('');

}

複製代碼

如上所示,使用 XOR 和一次性的密鑰 key 對密碼進行加密處理,只要 key 沒有泄露,目標文本就不會被破解。

上面說了那麼多,問題就來了:咱們應該使用什麼樣的哈希算法呢?

(1)選擇通過驗證的成熟算法,如 PBKDF2 等 ;

(2)crypt 的安全版本;

(3)避免使用本身設計的加密算法。

HMAC

對於HMAC算法,我也不是太瞭解.看了幾篇文章,感受和加鹽很像,就是salt換成後端隨機生成的(好像能夠防止重放攻擊).而後再經過HMAC算法,獲得摘要.

關於HMAC算法部分能夠詳細看這篇文章,我是學渣,看了半天也不是太懂.=.=

大概過程以下:

  • 1.客戶端發出登陸請求
  • 2.服務器返回一個隨機值,在會話記錄中保存這個隨機值
  • 3.客戶端將該隨機值做爲密鑰,用戶密碼進行 hmac 運算,遞交給服務器
  • 4.服務器讀取數據庫中的用戶密碼,利用密鑰作和客戶端同樣的 hmac運算,而後與用戶發送的結果比較,若是一致,則用戶身份合法。

好處:

  • 與自定義的加salt算法不一樣,Hmac算法針對全部哈希算法都通用,不管是MD5仍是SHA-1。採用Hmac替代咱們本身的salt算法,可使程序算法更標準化,也更安全。(摘自雪峯大佬的這篇文章)
  • 另一個就是密碼的安全性,因爲不知道密鑰,因此不可能獲取到用戶密碼

補充1: 結合驗證碼進行前端加密 (其實就是一種動態加鹽哈希)

前端先將密碼哈希,而後和用戶輸入的驗證碼進行哈希,獲得的結果做爲密碼字段發送給服務器。服務器先確認驗證碼正確,而後再進行密碼驗證,不然直接返回驗證碼錯誤信息。

這種實踐保證了密碼在傳輸過程當中的資料安全,即便攻擊者拿到了數據也沒法重放。圖形化驗證碼更是增長了難度。另外一方面該實踐大大增長了撞庫的成本。

前端加密必定程度保障了傳輸過程當中的資料安全,那麼會不會有對兩端(客戶端和服務器)有安全幫助呢?

有幫助,使用一些前端加密手段,能夠增長拖庫後的數據破解難度。可是驗證碼方法不具備這樣的功能,由於數據庫存的還是明文密碼哈希後的結果,那麼攻擊者能夠繞過前端加密,能夠直接暴力破解。

補充2: Base64 編碼

你們常常說的是 Base64 加密,有 Base64 加密嗎?真木有,只有 Base64 編碼。

Base64 是一種基於 64 個可打印字符來表示二進制數據的表示方法。經常使用於在一般處理文本數據的場合,表示、傳輸、存儲一些二進制數據,包括 MIME 的 email,email via MIME,在 XML 中存儲複雜數據;主要用來解決把不可打印的內容塞進可打印內容的需求。js中 base64 方法使用以下:

//1.編碼
var result = Base.encode('shotCat好帥!');  //--> "c2hvdENhdOWlveW4hSE="

//2.解碼
var result2 = Base.decode(result); //--> 'shotCat好帥!' 沒錯,我就是這麼不要臉!!!

複製代碼

所以,Base64 適用於小段內容的編碼,好比數字證書籤名、Cookie的內容等;並且 Base64 也是一種經過查表的編碼方法,不能用於加密,若是須要加密,請使用專業的加密算法。

PS: 對於前端來講,base64用得最多的也就是圖片轉碼吧.

補充3: 數字簽名

數字簽名主要用於:確認信息來源於特定的主體且信息完整、未被篡改,發送方生成簽名,接收方驗證簽名。

發送方: 首先計算目標文本的摘要(哈希值),經過私鑰對摘要進行簽名,將目標文本和電子簽名發送給接收方。

接收方: 驗證簽名的步驟以下:

  • 1,經過公鑰破解電子簽名,獲得摘要 D1 (若是失敗,則信息來源主體校驗失敗);
  • 2,計算目標文本摘要 D2;
  • 3,若 D1 === D2,則說明目標文本完整、未被篡改。

數字簽名與非對稱加密區別:

  • 非對稱加密(加密/解密):公鑰加密,私鑰解密。
  • 數字簽名(簽名/驗證):私鑰簽名,公鑰驗證。

HTTPS加密

爲了不重複,這部份內容在本系列-HTTP與HTTPS有詳細介紹

感謝及參考

相關文章
相關標籤/搜索