如何加密傳輸和儲存使用者密碼

徐辛承發表於2018-05-11

為什麼寫這篇文章

近期,Github被爆出,在內部日誌中記錄了明文密碼。

雖然據說影響面很小,但是網路和資料安全問題又一次被放到檯面上。大多數使用者的常用密碼就那麼幾個,一旦被黑客拿到,去其他網站“撞庫”,可能會造成使用者的財產損失。

本篇文章主要介紹如何加密傳輸和儲存使用者密碼,並講解相關原理。

加密傳輸

加密主要有兩種方式:對稱加密和非對稱加密。

對稱加密

對稱加密:在加密和解密時使用的是同一個祕鑰。

對稱加密的模式是:

  • 甲方選擇某一種加密規則,對資訊進行加密
  • 乙方使用同一種規則,對資訊進行解密

客戶端和服務端進行通訊,採用對稱加密,如果只使用一個祕鑰,很容易破解;如果每次用不同的祕鑰,海量祕鑰的管理和傳輸成本又會比較高。

非對稱加密

非對稱加密:需要兩個金鑰來進行加密和解密,這兩個祕鑰是公開金鑰(public key,簡稱公鑰)和私有金鑰(private key,簡稱私鑰)。

非對稱加密的模式則是:

  • 乙方生成兩把金鑰(公鑰和私鑰)。公鑰是公開的,任何人都可以獲得,私鑰則是保密的
  • 甲方獲取乙方的公鑰,然後用它對資訊加密
  • 乙方得到加密後的資訊,用私鑰解密。

即使黑客拿到了公鑰,沒有私鑰也是沒有辦法解密,不考慮彩虹表的情況,完全可以長期使用一對祕鑰。

RSA

最經典的非對稱加密演算法是RSA演算法。

RSA公鑰加密演算法是1977年由羅納德·李維斯特(Ron Rivest)、阿迪·薩莫爾(Adi Shamir)和倫納德·阿德曼(Leonard Adleman)一起提出的。公鑰私鑰成對出現,用其中一個加密只能用另一個解密,通常用公鑰加密私鑰解密。

為什麼RSA能夠做到非對稱加密呢?

互質關係:如果兩個正整數,除了1以外,沒有其他公因子,我們就稱這兩個數是互質關係

簡單來說,RSA利用的原理是,如果兩個互質關係的正整數的乘積足夠大,是極難進行因式分解的(目前被破解的最長RSA金鑰是768個二進位制位,而正常使用的至少是1024位的金鑰)。

通過一定的運算,把某計算結果和乘積作為公鑰,另一個計算結果和乘積作為私鑰,即可以實現,利用公鑰進行加密,並利用私鑰進行解密。具體的數學公式推導和證明可以參考RSA演算法原理

github的登入方式

傳輸層面的加密解密原理講的差不多了,我們來看看github是如何傳輸賬號密碼的。

抓包看一下登入請求的request,赫然發現,密碼是通過明文傳輸的……

image

那麼,這種傳輸方式安全嘛?還可以,因為使用了https,但還不夠安全。

http和https

常規的http請求,所有資訊明文傳播,只要中間人在鏈路中的任意階段進行劫持,就會帶來三大風險:

  • 竊聽風險(eavesdropping):第三方可以獲知通訊內容。
  • 篡改風險(tampering):第三方可以修改通訊內容。
  • 冒充風險(pretending):第三方可以冒充他人身份參與通訊。

怎麼解決這些問題?用https。

https 可以認為是 http + TLS TLS 是傳輸層加密協議,它的前身是 SSL 協議,如果沒有特別說明,SSL 和 TLS 說的都是同一個協議。

SSL/TLS協議是為了解決http的三大風險而設計的,希望達到:

  • 內容加密。所有資訊都是加密傳播,第三方無法竊聽。
  • 身份認證。配備身份證照,防止身份被冒充。即使被 DNS 劫持到了第三方站點,也會提醒使用者有可能被劫持
  • 資料完整性。防止內容被第三方冒充或者篡改。具有校驗機制,一旦被篡改,通訊雙方會立刻發現。

說了這麼多,https做了什麼?結合以下流程圖,講解一次https請求都發生了什麼:

image

  1. 客戶端發起https請求

  2. 服務端的配置

一般需要向權威機構申請一個證照(也可以自己製作,這個會在之後的中間人攻擊中講到,區別就是自己頒發的證照需要客戶端驗證通過,才可以繼續訪問,而使用受信任的公司申請的證照則不會提示),證照會生成RSA加密使用的一對公鑰A和私鑰B。

  1. 傳送證照

這個證照主要內容是公鑰A,也包含了其他資訊,如證照的頒發機構,過期時間等等。

  1. 客戶端解析證照

由客戶端的TLS來完成的,主要是驗證公鑰A是否有效,比如頒發機構,過期時間等等,如果發現異常,則會彈出一個警告框,提示證照存在問題。如果證照沒有問題,那麼就生成一個隨機值。之後就進入了不對稱加密的過程,首先用證照對該隨機值進行加密。

  1. 傳送加密資訊

這部分傳送的是用證照加密後的隨機值,目的就是讓服務端得到這個隨機值,後續所有的資料都可以用這個隨機值(即私鑰C),進行對稱加密和解密。

  1. 服務端解密資訊

服務端用私鑰B解密後,得到了客戶端傳過來的私鑰C,到此RSA非對稱加密的過程結束了。

  1. 傳輸加密後的資訊

服務端用私鑰C加密資訊。

  1. 客戶端解密資訊

客戶端用之前生成的私鑰C解密服務端傳過來的資訊,於是獲取瞭解密後的內容。整個過程第三方即使監聽到了資料,也束手無策。

中間人攻擊(MITM)

上面的過程,看起來似乎無懈可擊?並不是,因為“人”才是安全系統中最脆弱的環節。

https資訊的安全,完全建立在證照可信的基礎上,如果中間人偽造證照怎麼辦?

黑客自己偽造的證照需要客戶端驗證通過,才可以繼續訪問,只要客戶端驗證通過,那麼公鑰A,私鑰B和私鑰C對黑客來說都是透明的,也有沒有資料安全可言了,所以黑客只要誘導使用者安裝自己偽造的證照即可,例如使用各種釣魚的不可描述網站。

所以即使使用https傳輸明文密碼,也不是絕對安全的。那怎麼樣才能保證密碼安全呢?

百度的登入方式

抓包看一下百度的登入請求發現,密碼是加密過的:

image

怎麼加密的?我們發現,有這麼一個關鍵請求:

image

意味著,密碼使用RSA進行加密和解密處理的。那麼流程是什麼樣的呢?

查了一下github中,關鍵詞RSA,star數最多的JavaScript庫jsencrypt,驚喜的發現,百度登入的加密方式和使用的函式名都和這個庫一致,那我們是不是可以大膽假設百度整套登入請求時的流程和這個開源庫基本一致呢,那jsencrypt的流程又是什麼樣的呢:

image

加密儲存

到這裡,加密傳輸的過程已經完結了,現在服務端已經收到了使用者真實的密碼(解密後的),那怎麼儲存這個密碼呢?

千萬不要用明文儲存密碼

如果用明文儲存密碼(不管是存在資料庫還是日誌中),一旦資料洩露,所有使用者的密碼就毫無保留地暴露在黑客的面前,開頭提到的風險就可能發生,那我們費半天勁加密傳輸密碼也失去了意義。

用雜湊演算法加密密碼

單向加密演算法:只能從明文生成一個對應的雜湊值,不能反過來根據雜湊值得到對應的明文。

常用的給密碼加密的演算法是幾種單向的雜湊演算法。

經常被大家用來加密的演算法有MD5和SHA系列(如SHA1、SHA256、SHA384、SHA512等)。

雖然用雜湊演算法能提高密碼儲存的安全性,但還是不夠安全。

通常黑客在侵入儲存密碼的資料庫之後,他會隨機猜測一個密碼,生成一個雜湊值。如果該雜湊值在資料庫中存在,那麼他就猜對了一個使用者的密碼。如果沒有猜中也沒有關係,他可以再次隨機猜測下一個密碼進行嘗試。

事實上黑客為了提高破解密碼的效率,他們會事先計算大量密碼對應的各種雜湊演算法的雜湊值,並把密碼及對應的雜湊值存入一個表格中(這種表格通常被稱為彩虹表),在破解密碼時只需要到事先準備的彩虹表裡匹配即可。因此現在黑客們破解僅僅只用雜湊演算法加密過的密碼事實上已是不費吹灰之力。

加“鹽”提高安全性

鹽:一個隨機的字串,往明文密碼里加鹽就是把明文密碼和一個隨機的字串拼接在一起。

為了應對黑客們用彩虹表破解密碼,我們可以先往明文密碼加鹽,然後再對加鹽之後的密碼用雜湊演算法加密。由於鹽在密碼校驗的時候還要用到,因此通常鹽和密碼的雜湊值是儲存在一起的。

採用加鹽的雜湊演算法對密碼加密,要確保要往每個密碼裡新增隨機的唯一的鹽,而不是讓所有密碼共享一樣的鹽。

雖然加鹽的演算法能有效應對彩虹表的破解法,但它的安全級別並不高,因為計算雜湊值耗時極短,黑客仍然可以用窮舉法來破解,只是增加了一些耗時。

用BCrypt或者PBKDF2增加破解的難度

為了應對暴力破解法,我們需要非常耗時的而不是非常高效的雜湊演算法。BCrypt和PBKDF2演算法應運而生。

這兩個演算法最大的特點是我們可以通過引數設定重複計算的次數,重複計算的次數越多耗時越長。如果計算一個雜湊值需要耗時1秒甚至更多,那麼黑客們採用暴利法破解密碼將幾乎不再可能。破解一個6位純數字密碼需要耗時11.5天,更不要說高安全級別的密碼了。

總結

如果我們想要儘可能保證使用者的資訊保安,我們需要做以下的工作

  • 使用https請求
  • 利用RSA加密密碼並傳輸資料
  • 用BCrypt或者PBKDF2單向加密,並儲存

以上。

相關文章