天天看點

徹底搞懂HTTPs的加密原理

連結:https://zhuanlan.zhihu.com/p/43789231

HTTPS(SSL/TLS)的加密機制雖然是大家都應了解的基本知識,但網上很多相關文章總會忽略一些内容,沒有闡明完整的邏輯脈絡,我當年學習它的時候也廢了挺大功夫。

對稱與非對稱加密、數字簽名、數字證書等,在學習過程中,除了了解“它是什麼”,你是否有想過“為什麼是它”?我認為了解了後者才真正了解了HTTPS的加密機制。

本文以問題的形式逐漸展開,一步步解開HTTPS的面紗,希望能幫助你徹底搞懂HTTPS。

因為http的内容是明文傳輸的,明文資料會經過中間代理伺服器、路由器、wifi熱點、通信服務營運商等多個實體節點,如果資訊在傳輸過程中被劫持,傳輸的内容就完全暴露了。劫持者還可以篡改傳輸的資訊且不被雙方察覺,這就是​<code>​中間人攻擊​</code>​。是以我們才需要對資訊進行加密。最容易了解的就是​<code>​對稱加密​</code>​ 。

簡單說就是有一個密鑰,它可以加密一段資訊,也可以對加密後的資訊進行解密,和我們日常生活中用的鑰匙作用差不多。

徹底搞懂HTTPs的加密原理

對稱加密(https://sectigostore.com/blog/types-of-encryption-what-to-know-about-symmetric-vs-asymmetric-encryption/)

如果通信雙方都各自持有同一個密鑰,且沒有别人知道,這兩方的通信安全當然是可以被保證的(除非密鑰被破解)。

然而最大的問題就是這個密鑰怎麼讓傳輸的雙方知曉,同時不被别人知道。如果由伺服器生成一個密鑰并傳輸給浏覽器,那在這個傳輸過程中密鑰被别人劫持到手了怎麼辦?之後他就能用密鑰解開雙方傳輸的任何内容了,是以這麼做當然不行。

換種思路?試想一下,如果浏覽器内部就預存了網站A的密鑰,且可以確定除了浏覽器和網站A,不會有任何外人知道該密鑰,那理論上用對稱加密是可以的,這樣浏覽器隻要預存好世界上所有HTTPS網站的密鑰就行了!這麼做顯然不現實。

怎麼辦?是以我們就需要​<code>​非對稱加密​</code>​ 。

簡單說就是有兩把密鑰,通常一把叫做公鑰、一把叫私鑰,用公鑰加密的内容必須用私鑰才能解開,同樣,私鑰加密的内容隻有公鑰能解開。

徹底搞懂HTTPs的加密原理

非對稱加密(https://sectigostore.com/blog/types-of-encryption-what-to-know-about-symmetric-vs-asymmetric-encryption/)

鑒于非對稱加密的機制,我們可能會有這種思路:伺服器先把公鑰以明文方式傳輸給浏覽器,之後浏覽器向伺服器傳資料前都先用這個公鑰加密好再傳,這條資料的安全似乎可以保障了!因為隻有伺服器有相應的私鑰能解開公鑰加密的資料。

然而反過來由伺服器到浏覽器的這條路怎麼保障安全?如果伺服器用它的私鑰加密資料傳給浏覽器,那麼浏覽器用公鑰可以解密它,而這個公鑰是一開始通過明文傳輸給浏覽器的,若這個公鑰被中間人劫持到了,那他也能用該公鑰解密伺服器傳來的資訊了。是以目前似乎隻能保證由浏覽器向伺服器傳輸資料的安全性(其實仍有漏洞,下文會說),那利用這點你能想到什麼解決方案嗎?

我們已經了解通過一組公鑰私鑰,可以保證單個方向傳輸的安全性,那用兩組公鑰私鑰,是否就能保證雙向傳輸都安全了?請看下面的過程:

某網站伺服器擁有公鑰A與對應的私鑰A’;浏覽器擁有公鑰B與對應的私鑰B’。

浏覽器把公鑰B明文傳輸給伺服器。

伺服器把公鑰A明文給傳輸浏覽器。

之後浏覽器向伺服器傳輸的内容都用公鑰A加密,伺服器收到後用私鑰A’解密。由于隻有伺服器擁有私鑰A’,是以能保證這條資料的安全。

同理,伺服器向浏覽器傳輸的内容都用公鑰B加密,浏覽器收到後用私鑰B’解密。同上也可以保證這條資料的安全。

的确可以!抛開這裡面仍有的漏洞不談(下文會講),HTTPS的加密卻沒使用這種方案,為什麼?很重要的原因是非對稱加密算法非常耗時,而對稱加密快很多。那我們能不能運用非對稱加密的特性解決前面提到的對稱加密的漏洞?

既然非對稱加密耗時,那非對稱加密+對稱加密結合可以嗎?而且得盡量減少非對稱加密的次數。當然是可以的,且非對稱加密、解密各隻需用一次即可。

請看一下這個過程:

某網站擁有用于非對稱加密的公鑰A、私鑰A’。

浏覽器向網站伺服器請求,伺服器把公鑰A明文給傳輸浏覽器。

浏覽器随機生成一個用于對稱加密的密鑰X,用公鑰A加密後傳給伺服器。

伺服器拿到後用私鑰A’解密得到密鑰X。

這樣雙方就都擁有密鑰X了,且别人無法知道它。之後雙方所有資料都通過密鑰X加密解密即可。

完美!HTTPS基本就是采用了這種方案。完美?還是有漏洞的。

徹底搞懂HTTPs的加密原理

中間人攻擊(https://blog.pradeo.com/man-in-the-middle-attack)

如果在資料傳輸過程中,中間人劫持到了資料,此時他的确無法得到浏覽器生成的密鑰X,這個密鑰本身被公鑰A加密了,隻有伺服器才有私鑰A’解開它,然而中間人卻完全不需要拿到私鑰A’就能幹壞事了。請看:

某網站有用于非對稱加密的公鑰A、私鑰A’。

中間人劫持到公鑰A,儲存下來,把資料包中的公鑰A替換成自己僞造的公鑰B(它當然也擁有公鑰B對應的私鑰B’)。

浏覽器生成一個用于對稱加密的密鑰X,用公鑰B(浏覽器無法得知公鑰被替換了)加密後傳給伺服器。

中間人劫持後用私鑰B’解密得到密鑰X,再用公鑰A加密後傳給伺服器。

這樣在雙方都不會發現異常的情況下,中間人通過一套“狸貓換太子”的操作,掉包了伺服器傳來的公鑰,進而得到了密鑰X。根本原因是浏覽器無法确認收到的公鑰是不是網站自己的,因為公鑰本身是明文傳輸的,難道還得對公鑰的傳輸進行加密?這似乎變成雞生蛋、蛋生雞的問題了。解法是什麼?

其實所有證明的源頭都是一條或多條不證自明的“公理”(可以回想一下數學上公理),由它推導出一切。比如現實生活中,若想證明某身份證号一定是小明的,可以看他身份證,而身份證是由政府作證的,這裡的“公理”就是“政府機構可信”,這也是社會正常運作的前提。

那能不能類似地有個機構充當網際網路世界的“公理”呢?讓它作為一切證明的源頭,給網站頒發一個“身份證”?

它就是CA機構,它是如今網際網路世界正常運作的前提,而CA機構頒發的“身份證”就是數字證書。

徹底搞懂HTTPs的加密原理

網站在使用HTTPS前,需要向CA機構申領一份數字證書,數字證書裡含有證書持有者資訊、公鑰資訊等。伺服器把證書傳輸給浏覽器,浏覽器從證書裡擷取公鑰就行了,證書就如身份證,證明“該公鑰對應該網站”。而這裡又有一個顯而易見的問題,“證書本身的傳輸過程中,如何防止被篡改”?即如何證明證書本身的真實性?身份證運用了一些防僞技術,而數字證書怎麼防僞呢?解決這個問題我們就接近勝利了!

我們把證書原本的内容生成一份“簽名”,比對證書内容和簽名是否一緻就能判别是否被篡改。這就是數字證書的“防僞技術”,這裡的“簽名”就叫​<code>​數字簽名​</code>​:

這部分内容建議看下圖并結合後面的文字了解,圖中左側是數字簽名的制作過程,右側是驗證過程:

徹底搞懂HTTPs的加密原理

數字簽名的生成與驗證(https://cheapsslsecurity.com/blog/digital-signature-vs-digital-certificate-the-difference-explained/)

數字簽名的制作過程:

CA機構擁有非對稱加密的私鑰和公鑰。

CA機構對證書明文資料T進行hash。

對hash後的值用私鑰加密,得到數字簽名S。

明文和數字簽名共同組成了數字證書,這樣一份數字證書就可以頒發給網站了。

那浏覽器拿到伺服器傳來的數字證書後,如何驗證它是不是真的?(有沒有被篡改、掉包)

浏覽器驗證過程:

拿到證書,得到明文T,簽名S。

用CA機構的公鑰對S解密(由于是浏覽器信任的機構,是以浏覽器保有它的公鑰。詳情見下文),得到S’。

用證書裡指明的hash算法對明文T進行hash得到T’。

顯然通過以上步驟,T’應當等于S‘,除非明文或簽名被篡改。是以此時比較S’是否等于T’,等于則表明證書可信。

為何麼這樣可以保證證書可信呢?我們來仔細想一下。

假設中間人篡改了證書的原文,由于他沒有CA機構的私鑰,是以無法得到此時加密後簽名,無法相應地篡改簽名。浏覽器收到該證書後會發現原文和簽名解密後的值不一緻,則說明證書已被篡改,證書不可信,進而終止向伺服器傳輸資訊,防止資訊洩露給中間人。

既然不可能篡改,那整個證書被掉包呢?

假設有另一個網站B也拿到了CA機構認證的證書,它想劫持網站A的資訊。于是它成為中間人攔截到了A傳給浏覽器的證書,然後替換成自己的證書,傳給浏覽器,之後浏覽器就會錯誤地拿到B的證書裡的公鑰了,這确實會導緻上文“中間人攻擊”那裡提到的漏洞?

其實這并不會發生,因為證書裡包含了網站A的資訊,包括域名,浏覽器把證書裡的域名與自己請求的域名比對一下就知道有沒有被掉包了。

我初識HTTPS的時候就有這個疑問,因為似乎那裡的hash有點多餘,把hash過程去掉也能保證證書沒有被篡改。

最顯然的是性能問題,前面我們已經說了非對稱加密效率較差,證書資訊一般較長,比較耗時。而hash後得到的是固定長度的資訊(比如用md5算法hash後可以得到固定的128位的值),這樣加解密就快很多。

當然也有安全上的原因,這部分内容相對深一些,感興趣的可以看這篇解答:​​crypto.stackexchange.com/a/12780​​

你們可能會發現上文中說到CA機構的公鑰,我幾乎一筆帶過,“浏覽器保有它的公鑰”,這是個什麼保有法?怎麼證明這個公鑰是否可信?

讓我們回想一下數字證書到底是幹啥的?沒錯,為了證明某公鑰是可信的,即“該公鑰是否對應該網站”,那CA機構的公鑰是否也可以用數字證書來證明?沒錯,作業系統、浏覽器本身會預裝一些它們信任的根證書,如果其中會有CA機構的根證書,這樣就可以拿到它對應的可信公鑰了。

實際上證書之間的認證也可以不止一層,可以A信任B,B信任C,以此類推,我們把它叫做​<code>​信任鍊​</code>​或​<code>​數字證書鍊​</code>​。也就是一連串的數字證書,由根證書為起點,透過層層信任,使終端實體證書的持有者可以獲得轉授的信任,以證明身份。

另外,不知你們是否遇到過網站通路不了、提示需安裝證書的情況?這裡安裝的就是根證書。說明浏覽器不認給這個網站頒發證書的機構,那麼你就得手動下載下傳安裝該機構的根證書(風險自己承擔XD)。安裝後,你就有了它的公鑰,就可以用它驗證伺服器發來的證書是否可信了。

徹底搞懂HTTPs的加密原理

信任鍊(https://publib.boulder.ibm.com/tividd/td/TRM/GC32-1323-00/en_US/HTML/admin230.htm)

這也是我當時的困惑之一,顯然每次請求都經曆一次密鑰傳輸過程非常耗時,那怎麼達到隻傳輸一次呢?

伺服器會為每個浏覽器(或用戶端軟體)維護一個session ID,在TLS握手階段傳給浏覽器,浏覽器生成好密鑰傳給伺服器後,伺服器會把該密鑰存到相應的session ID下,之後浏覽器每次請求都會攜帶session ID,伺服器會根據session ID找到相應的密鑰并進行解密加密操作,這樣就不必要每次重新制作、傳輸密鑰了!

可以看下這張圖,梳理一下整個流程(SSL、TLS握手有一些差別,不同版本間也有差別,不過大緻過程就是這樣):

徹底搞懂HTTPs的加密原理

(www.extremetech.com)

至此,我們已自上而下地打通了HTTPS加密的整體脈絡以及核心知識點,不知你是否真正搞懂了HTTPS呢?

找幾個時間,多看、多想、多了解幾次就會越來越清晰的!

那麼,下面的問題你是否已經可以解答了呢?

為什麼要用對稱加密+非對稱加密?

為什麼不能隻用非對稱加密?

為什麼需要數字證書?

為什麼需要數字簽名?

繼續閱讀