HTTPS(SSL/TLS)的加密機制雖然是個前端後端開發都應瞭解的基本問題,但網上的不少HTTPS相關文章也總會忽略一些內容,我學習它的時候也廢了挺大功夫。
對稱加密、非對稱加密、數字簽名、數字證書等等,在學習過程當中,除了瞭解「它是什麼」,你是否有想過「爲何是它」?我認爲理解了後者才真正理解了HTTPS的加密機制。
本文以問題的形式逐步展開,一步步解開HTTPS的面紗,但願能幫助你完全搞懂HTTPS。特別是對於瞭解過HTTPS卻在有些地方有所卡殼的人,但願本文能幫助你理清思路。前端
由於http的內容是明文傳輸的,明文數據會通過中間代理服務器、路由器、wifi熱點、通訊服務運營商等多個物理節點,若是信息在傳輸過程當中被劫持,傳輸的內容就徹底暴露了,他還能夠篡改傳輸的信息且不被雙方察覺,這就是中間人攻擊
。因此咱們才須要對信息進行加密。最直接的加密方式就是對稱加密
。git
就是有一個密鑰,它能夠對一段內容加密,加密後只能用它才能解密看到本來的內容,和咱們平常生活中用的鑰匙做用差很少。github
若是通訊雙方都各自持有同一個密鑰,且沒有別人知道,這兩方的通訊安全固然是能夠被保證的(除非密鑰被破解)。
然而最大的問題就是這個密鑰怎麼讓傳輸的雙方知曉,同時不被別人知道。若是由服務器生成一個密鑰並傳輸給瀏覽器,那這個傳輸過程當中密鑰被別人劫持弄到手了怎麼辦?以後他就能用密鑰解開雙方傳輸的任何內容了,因此這麼作固然不行。
換種思路?試想一下,若是瀏覽器內部就預存了網站A的密鑰,且能夠確保除了瀏覽器和網站A,不會有任何外人知道該密鑰,那理論上用對稱加密是能夠的,這樣瀏覽器只要預存好世界上全部HTTPS網站的密鑰就行啦!這麼作顯然不現實。
怎麼辦?因此咱們就須要神奇的非對稱加密
算法
有兩把密鑰,一般一把叫作公鑰、一把叫作私鑰,用公鑰加密的內容必須用私鑰才能解開,一樣,私鑰加密的內容只有公鑰能解開。後端
鑑於非對稱加密的機制,咱們可能會有這種思路:服務器先把公鑰直接明文傳輸給瀏覽器,以後瀏覽器向服務器傳數據前都先用這個公鑰加密好再傳,這條數據的安全彷佛能夠保障了!由於只有服務器有相應的私鑰能解開這條數據。
然而由服務器到瀏覽器的這條路怎麼保障安全?若是服務器用它的的私鑰加密數據傳給瀏覽器,那麼瀏覽器用公鑰能夠解密它,而這個公鑰是一開始經過明文傳輸給瀏覽器的,這個公鑰被誰劫持到的話,他也能用該公鑰解密服務器傳來的信息了。因此目前彷佛只能保證由瀏覽器向服務器傳輸數據時的安全性(其實仍有漏洞,下文會說),那利用這點你能想到什麼解決方案嗎?瀏覽器
咱們已經理解經過一組公鑰私鑰,已經能夠保證單個方向傳輸的安全性,那用兩組公鑰私鑰,是否是就能保證雙向傳輸都安全了?請看下面的過程:安全
的確能夠!拋開這裏面仍有的漏洞不談(下文會講),HTTPS的加密卻沒使用這種方案,爲何?最主要的緣由是非對稱加密算法很是耗時,特別是加密解密一些較大數據的時候有些力不從心,而對稱加密快不少,看來必須得用對稱加密,那咱們能不能運用非對稱加密的特性解決前面提到的對稱加密的問題?服務器
既然非對稱加密耗時,非對稱加密+對稱加密結合能夠嗎?並且得儘可能減小非對稱加密的次數。固然是能夠的,並且非對稱加密、解密各只需用一次便可。
請看一下這個過程:session
完美!HTTPS基本就是採用了這種方案。完美?仍是有漏洞的。性能
中間人的確沒法獲得瀏覽器生成的密鑰B,這個密鑰自己被公鑰A加密了,只有服務器纔有私鑰A’解開拿到它呀!然而中間人卻徹底不須要拿到密鑰A’就能幹壞事了。請看:
這樣在雙方都不會發現異常的狀況下,中間人獲得了密鑰B。根本緣由是瀏覽器沒法確認本身收到的公鑰是否是網站本身的。那麼下一步就是解決下面這個問題:
現實生活中,若是想證實某身份證號必定是小明的,怎麼辦?看身份證。這裏政府機構起到了「公信」的做用,身份證是由它頒發的,它自己的權威能夠對一我的的身份信息做出證實。互聯網中能不能搞這麼個公信機構呢?給網站頒發一個「身份證」?
網站在使用HTTPS前,須要向「CA機構」申請頒發一份數字證書,數字證書裏有證書持有者、證書持有者的公鑰等信息,服務器把證書傳輸給瀏覽器,瀏覽器從證書裏取公鑰就好了,證書就如身份證同樣,能夠證實「該公鑰對應該網站」。然而這裏又有一個顯而易見的問題了,證書自己的傳輸過程當中,如何防止被篡改?即如何證實證書自己的真實性?身份證有一些防僞技術,數字證書怎麼防僞呢?解決這個問題咱們就基本接近勝利了!
咱們把證書內容生成一份「簽名」,比對證書內容和簽名是否一致就能察覺是否被篡改。這種技術就叫數字簽名
:
這部份內容建議看下圖並結合後面的文字理解,圖中左側是數字簽名的製做過程,右側是驗證過程(原圖出處找不到了,能夠看出來這圖已經被轉載了無數次了。。。)
數字簽名的製做過程:
明文和數字簽名共同組成了數字證書,這樣一份數字證書就能夠頒發給網站了。
那瀏覽器拿到服務器傳來的數字證書後,如何驗證它是否是真的?(有沒有被篡改、掉包)
瀏覽器驗證過程:
爲何這樣能夠證實證書可信呢?咱們來仔細想一下。
假設中間人篡改了證書的原文,因爲他沒有CA機構的私鑰,因此沒法獲得此時加密後簽名,沒法相應地篡改簽名。瀏覽器收到該證書後會發現原文和簽名解密後的值不一致,則說明證書已被篡改,證書不可信,從而終止向服務器傳輸信息,防止信息泄露給中間人。
既然不可能篡改,那整個證書被掉包呢?
假設有另外一個網站B也拿到了CA機構認證的證書,它想搞垮網站A,想劫持網站A的信息。因而它成爲中間人攔截到了A傳給瀏覽器的證書,而後替換成本身的證書,傳給瀏覽器,以後瀏覽器就會錯誤地拿到B的證書裏的公鑰了,會致使上文提到的漏洞。
其實這並不會發生,由於證書裏包含了網站A的信息,包括域名,瀏覽器把證書裏的域名與本身請求的域名比對一下就知道有沒有被掉包了。
我初學HTTPS的時候就有這個問題,彷佛以上過程當中hash有點多餘,把hash過程去掉也能保證證書沒有被篡改。
最顯然的是性能問題,前面咱們已經說了非對稱加密效率較差,證書信息通常較長,比較耗時。而hash後獲得的是固定長度的信息(好比用md5算法hash後能夠獲得固定的128位的值),這樣加密解密就會快不少。
固然還有安全上的緣由,這部份內容相對深一些,感興趣的能夠看這篇解答:crypto.stackexchange.com/a/12780
大家可能會發現上文中說到CA機構的公鑰,我幾乎一筆帶過,「瀏覽器保有它的公鑰」,這是個什麼保有法?怎麼證實這個公鑰是否可信?
讓咱們回想一下數字證書究竟是幹啥的?沒錯,爲了證實某公鑰是可信的,即「該公鑰是否對應該網站/機構等」,那這個CA機構的公鑰是否是也能夠用數字證書來證實?沒錯,操做系統、瀏覽器自己會預裝一些它們信任的根證書,若是其中有該CA機構的根證書,那就能夠拿到它對應的可信公鑰了。
實際上證書之間的認證也能夠不止一層,能夠A信任B,B信任C,以此類推,咱們把它叫作信任鏈
或數字證書鏈
,也就是一連串的數字證書,由根證書爲起點,透過層層信任,使終端實體證書的持有者能夠得到轉授的信任,以證實身份。
另外,不知大家是否遇到過網站訪問不了、提示要安裝證書的狀況?這裏安裝的就是跟證書。說明瀏覽器不認給這個網站頒發證書的機構,那麼沒有該機構的根證書,你就得手動下載安裝(風險本身承擔XD)。安裝該機構的根證書後,你就有了它的公鑰,就能夠用它驗證服務器發來的證書是否可信了。
這也是我當時的困惑之一,顯然每次請求都經歷一次密鑰傳輸過程很是耗時,那怎麼達到只傳輸一次呢?用session就行。
服務器會爲每一個瀏覽器(或客戶端軟件)維護一個session ID,在TSL握手階段傳給瀏覽器,瀏覽器生成好密鑰傳給服務器後,服務器會把該密鑰存到相應的session ID下,以後瀏覽器每次請求都會攜帶session ID,服務器會根據session ID找到相應的密鑰並進行解密加密操做,這樣就沒必要要每次從新制做、傳輸密鑰了!
能夠看下這張圖,梳理一下整個流程(SSL、TSL握手有一些區別,不一樣版本間也有區別,不過大體過程就是這樣):
(出處:www.extremetech.com)
至此,咱們已自下而上地打通了HTTPS加密的整個脈絡以及核心知識點,不知你是否真正搞懂了HTTPS呢?
找幾個時間,多看、多想、多理解幾回就會愈來愈清晰的!
那麼,下面的問題你是否已經能夠解答了呢?
固然,因爲篇幅所限和能力所限,一些更深刻的內容沒有覆蓋到。但我認爲通常對於先後端工程師來講,瞭解到這步就夠了,有興趣的能夠再深刻研究~若有疏漏之處,歡迎指出。
這篇文章也是對我學習時的一些總結和個人一些理解,一共花了快一天才寫完。若是你喜歡這篇文章,歡迎點贊分享~感謝!