傳統的不使用SSL/TLS的HTTP協議,是不加密的通訊。不管是客戶端發送給服務端的請求體,仍是服務端響應給客戶端的響應體,都是明文傳輸的,這會帶來幾個問題:算法
1. 竊聽 第三方劫持請求後能夠獲取通訊內容。對於一些敏感數據,這是不被容許的。瀏覽器
2. 篡改 第三方劫持請求後能夠篡改通訊內容。例如銀行系統中,張三原本要給李四轉帳,第三方劫持請求後篡改了請求數據,將收款方改成本身,致使用戶資金流失。安全
3. 冒充 第三方能夠冒充客戶端發送數據。因爲是明文傳輸,沒有「加簽/驗籤」操做,服務端沒法保證請求來源的合法性。服務器
正是由於這些問題,HTTP通訊存在巨大的安全隱患,因而HTTPS出現了。 本文將一步步深刻,看看HTTPS是如何解決這些問題的。markdown
在介紹HTTPS以前,必須先了解SSL/TLS協議,由於HTTPS是構建在此基礎之上的,瞭解了SSL/TLS基本也就清楚HTTPS的工做原理了。網絡
SSL(Secure Sockets Layer)譯爲「安全套接字協議」,TLS(Transport Layer Security)譯爲「傳輸層安全性協議」。性能
簡單回顧一下它們的發展歷史吧:網站
SSL/TLS協議處於「傳輸層」和「應用層」之間,主要做用是對網絡鏈接進行加解密,以下圖: 加密
先來看看第一個問題:竊聽。既然明文傳輸能夠被第三方竊聽數據,那麼改成加密傳輸不就好了嗎? 方向是對的,可是如何加密才能保證數據的安全呢?spa
採用單鑰密碼系統的加密方法,同一個密鑰能夠同時用做信息的加密和解密,這種加密方法稱爲對稱加密,也稱爲單密鑰加密。
例如DES就是一種對稱加密算法,甲乙雙方約定一個密鑰「Key」,雙方發送數據前都用該密鑰對數據進行加密傳輸,收到數據後再解密成明文便可。這種方式,只要保證密鑰不被泄漏,理論上也是安全的。
可是這會帶來一個新的問題:密鑰如何保存?
對於PC端來講,瀏覽器頁面是明文的,確定不能存儲密鑰。對於iOS/Android來講,即便把密鑰藏在安裝包的某個位置,也很容易被第三方拆包破解。
既然客戶端保存不靠譜,那麼密鑰只在服務端保存,客戶端去向服務端拿密鑰是否可行?
依然不可行,服務端要怎麼把密鑰給你呢?明文確定不行,若是要加密,又要用到密鑰B,密鑰B的傳輸又要用到密鑰C,如此循環,無解。
非對稱加密算法須要兩個密鑰:公開密鑰(publickey:簡稱公鑰)和私有密鑰(privatekey:簡稱私鑰)。公鑰與私鑰是一對,若是用公鑰對數據進行加密,只有用對應的私鑰才能解密。由於加密和解密使用的是兩個不一樣的密鑰,因此這種算法叫做非對稱加密算法。
甲乙雙方各有一套本身的密鑰對,互相公開彼此的公鑰,當甲方要發送數據給乙方時,用乙方公鑰加密,這樣密文就只有乙方本身能解開了,就算請求被劫持,第三方拿到了數據,因爲沒有乙方的私鑰,也沒法解密,這樣就保證了數據被竊聽。
單向非對稱加密 絕大多數互聯網網站對外是徹底公開的,全部人均可以訪問,服務端不必驗證全部客戶端的合法性,只有客戶端須要驗證服務端的合法性。例如用戶在訪問電商網站時,必須確保不是釣魚網站,以防資金損失。
這種狀況下,只須要單向加密便可。服務端發送給客戶端的通常不會有敏感信息,明文傳輸便可。可是客戶端發送給服務端的就頗有多是敏感信息,例如用戶修改密碼,這時就必須加密傳輸了。
雙向非對稱加密 有時,服務端也須要驗證客戶端的合法性,例如銀行系統。因爲涉及到金錢,所以系統必須設計的足夠安全。除了客戶端發送給服務端的數據是加密的,服務端發送給客戶端的數據也必須加密。
怎麼作的呢?通常銀行會給用戶一個U盤,裏面存儲的就是一套密鑰對,客戶端告訴服務端本身的公鑰,服務端根據公鑰加密後再傳輸給客戶端。
經過非對稱加密的密文傳輸,能夠防止數據被竊聽,可是若是存在這種場景呢?
張三登錄銀行系統,要給李四轉一筆錢,數據經過服務端的公鑰PubB加密傳輸,可是第三方劫持了這個請求,篡改了報文數據,寫入的是「給王五轉錢」,由於服務端的公鑰是公開的,誰都能拿到,所以第三方也能夠正常加密傳輸,服務端正常解密後進行了錯誤的操做,致使用戶資金流失。
對於涉及到資金的操做,服務端必需要驗證數據的合法性,確保數據沒有被篡改,這就須要客戶端對數據進行加簽了。
非對稱加密除了能夠「公鑰加密,私鑰解密」外,還能夠「私鑰加簽,公鑰驗籤」。
銀行給用戶一個U盤,裏面有一套密鑰對。客戶端在發送轉帳請求前,先對請求體加簽,獲得簽名「sign」,而後再用服務端公鑰加密,獲得密文「data」,客戶端將簽名和密文一塊兒發送給服務端,服務端解密後,還須要用客戶端的公鑰對「sign」進行驗籤,只有驗籤經過才能進行後續操做,不然就是非法請求了。 這樣,即便請求被第三方劫持了,第三方能夠篡改數據,可是簽名它改不了,服務端解密後會發現數據和「sign」對不上,說明數據是被篡改過的。
經過加密防止數據被竊聽,經過加簽防止數據被篡改,如今看來好像已經很安全了,可是別忘了,有個前提是:公鑰的傳輸是安全的。不幸的是,公鑰的安全傳輸很難保證。
中間人攻擊 假設存在這樣一種場景,客戶端和服務端想互換公鑰,可是請求都被一箇中間人劫持了,結果就是:服務端和客戶端覺得是和雙方互換公鑰了,結果是客戶端和服務端都和中間人互換公鑰了。 一旦出現這種問題就很是嚴重,前面講到的加密解密、加簽驗籤都失效了。客戶端覺得中間人就是服務端,服務端覺得中間人就是客戶端,雙方覺得是在和對方通訊,其實都是在和中間人通訊,中間人能夠隨意的竊聽和篡改數據。
這個問題之因此會出現,就是由於公鑰的傳輸是不安全的。客戶端和服務端之間互換公鑰時,如何確保公鑰就是對方發出的,沒有被篡改過呢???
在以前的基礎上,引入一箇中間角色:證書認證中心CA。當服務端要把公鑰發送給客戶端時,不是直接發送公鑰,而是先把公鑰發送給CA,CA根據公鑰生成一份「證書」給到服務端,服務端將證書給客戶端。客戶端拿到證書後去CA驗證證書的合法性,確保證書是服務端下發的。
CA就相似於「公證處」,也是一臺服務器,它本身自己也有一套密鑰對。它的工做就是根據服務端的公鑰生成證書,而後幫助客戶端來驗證證書的合法性。
引入CA能夠保證公鑰的傳輸安全,可是有一個前提,客戶端和服務端是信任CA的,也就是說CA必須是安全可信任的,若是CA被冒充,就又會出現上面的問題。 基於這個問題,就引入了「根證書」和「CA信任鏈」的概念。
要讓客戶端和服務端信任CA,其實CA也面臨着一樣的問題,那就是:如何保證CA的公鑰是安全不被篡改的?答案也是同樣的,就是給CA也頒發證書,那這個證書由誰來頒發呢?天然是CA的上一級CA了。CA的上一級CA如何保證安全?那就CA的上一級CA的上一級CA給它頒發證書了。最終就會造成一個證書信用鏈,以下: 客戶端要想驗證服務器的C3證書是否合法,會跑去CA2驗證,要驗證CA2就去CA1驗證,以此類推。對於根證書,是無法驗證的,只能無條件相信。由於Root CA都是國際上公認的機構,通常用戶的操做系統或瀏覽器在發佈時,就會在裏面嵌入這些機構的Root證書。
以下是百度官網的證書,點擊瀏覽器地址欄旁邊的鎖標識就能看到了。
瞭解了底層的實現,加密、加簽、證書等概念後,再來看SSL/TLS協議就很容易理解了。SSL/TLS須要四次握手的過程:
瞭解SSL/TLS,再回過頭來看HTTPS就很簡單了,HTTPS=HTTP+SSL/TLS。
使用HTTPS進行通訊時,先是創建傳輸層TCP的鏈接,完成三次握手,而後再是SSL/TLS協議的四次握手,雙方協商出對稱加密的密鑰,以後的通訊數據會利用該密鑰進行加密傳輸。 HTTP1.1開始支持長鏈接了,只要鏈接不關閉,七次握手只須要執行一次,性能損耗不會太大,並且數據傳輸採用的是對稱加密,相比於非對稱加密,性能損耗也小得多。所以HTTPS相比於HTTP,性能會有必定影響,但不會太大,相比之下,數據傳輸安全顯得更加劇要!