要說清楚 https 協定的實作原理,至少需要如下幾個背景知識。
大緻了解幾個基本術語(https、ssl、tls)的含義
大緻了解 http 和 tcp 的關系(尤其是“短連接配接”vs“長連接配接”)
大緻了解加密算法的概念(尤其是“對稱加密與非對稱加密”的差別)
大緻了解 ca 證書的用途
考慮到很多技術菜鳥可能不了解上述背景,俺先用最簡短的文字描述一下。如果你自認為不是菜鳥,請略過本章節,直接去看“https 協定的需求”。

首先,http 是一個網絡協定,是專門用來幫你傳輸 web 内容滴。關于這個協定,就算你不了解,至少也聽說過吧?比如你通路俺的部落格的首頁,浏覽器位址欄會出現如下的網址 http://program-think.blogspot.com/
俺加了粗體的部分就是指 http 協定。大部分網站都是通過 http 協定來傳輸 web 頁面、以及 web 頁面上包含的各種東東(圖檔、css 樣式、js 腳本)。
為啥要發明 ssl 這個協定捏?因為原先網際網路上使用的 http 協定是明文的,存在很多缺點——比如傳輸内容會被偷窺(嗅探)和篡改。發明 ssl 協定,就是為了解決這些問題。
到了1999年,ssl 因為應用廣泛,已經成為網際網路上的事實标準。ietf 就在那年把 ssl 标準化。标準化之後的名稱改為 tls(是“transport layer security”的縮寫),中文叫做“傳輸層安全協定”。
很多相關的文章都把這兩者并列稱呼(ssl/tls),因為這兩者可以視作同一個東西的不同階段。
3. “https”是啥意思?
解釋完 http 和 ssl/tls,現在就可以來解釋 https 啦。咱們通常所說的 https 協定,說白了就是“http 協定”和“ssl/tls 協定”的組合。你可以把 https 大緻了解為——“http over ssl”或“http over tls”(反正 ssl 和 tls 差不多)。
<a target="_blank"></a>
作為背景知識介紹,還需要再稍微談一下 http 協定本身的特點。http 本身有很多特點,考慮到篇幅有限,俺隻談那些和 https 相關的特點。
在 1.1 之前,還有曾經出現過兩個版本“0.9 和 1.0”,其中的 http 0.9 【沒有】被廣泛使用,而 http 1.0 被廣泛使用過。
簡單地說,tcp 協定是 http 協定的基石——http 協定需要依靠 tcp 協定來傳輸資料。
在網絡分層模型中,tcp 被稱為“傳輸層協定”,而 http 被稱為“應用層協定”。有很多常見的應用層協定是以 tcp 為基礎的,比如“ftp、smtp、pop、imap”等。
tcp 被稱為“面向連接配接”的傳輸層協定。關于它的具體細節,俺就不展開了(否則篇幅又失控了)。你隻需知道:傳輸層主要有兩個協定,分别是 tcp 和 udp。tcp 比 udp 更可靠。你可以把 tcp 協定想象成某個水管,發送端這頭進水,接收端那頭就出水。并且 tcp 協定能夠確定,先發送的資料先到達(與之相反,udp 不保證這點)。
http 對 tcp 連接配接的使用,分為兩種方式:俗稱“短連接配接”和“長連接配接”(“長連接配接”又稱“持久連接配接”,洋文叫做“keep-alive”或“persistent connection”)
假設有一個網頁,裡面包含好多圖檔,還包含好多【外部的】css 檔案和 js 檔案。在“短連接配接”的模式下,浏覽器會先發起一個 tcp 連接配接,拿到該網頁的 html 源代碼(拿到 html 之後,這個 tcp 連接配接就關閉了)。然後,浏覽器開始分析這個網頁的源碼,知道這個頁面包含很多外部資源(圖檔、css、js)。然後針對【每一個】外部資源,再分别發起一個個 tcp 連接配接,把這些檔案擷取到本地(同樣的,每抓取一個外部資源後,相應的 tcp 就斷開)
相反,如果是“長連接配接”的方式,浏覽器也會先發起一個 tcp 連接配接去抓取頁面。但是抓取頁面之後,該 tcp 連接配接并不會立即關閉,而是暫時先保持着(所謂的“keep-alive”)。然後浏覽器分析 html 源碼之後,發現有很多外部資源,就用剛才那個 tcp 連接配接去抓取此頁面的外部資源。
在 http 1.0 版本,【預設】使用的是“短連接配接”(那時候是 web 誕生初期,網頁相對簡單,“短連接配接”的問題不大);
到了1995年底開始制定 http 1.1 草案的時候,網頁已經開始變得複雜(網頁内的圖檔、腳本越來越多了)。這時候再用短連接配接的方式,效率太低下了(因為建立 tcp 連接配接是有“時間成本”和“cpu 成本”滴)。是以,在 http 1.1 中,【預設】采用的是“keep-alive”的方式。
通俗而言,你可以把“加密”和“解密”了解為某種【互逆的】數學運算。就好比“加法和減法”互為逆運算、“乘法和除法”互為逆運算。
“加密”的過程,就是把“明文”變成“密文”的過程;反之,“解密”的過程,就是把“密文”變為“明文”。在這兩個過程中,都需要一個關鍵的東東——叫做“密鑰”——來參與數學運算。
所謂的“對稱加密技術”,意思就是說:“加密”和“解密”使用【相同的】密鑰。這個比較好了解。就好比你用 7zip 或 winrar 建立一個帶密碼(密碼)的加密壓縮包。當你下次要把這個壓縮檔案解開的時候,你需要輸入【同樣的】密碼。在這個例子中,密碼/密碼就如同剛才說的“密鑰”。
所謂的“非對稱加密技術”,意思就是說:“加密”和“解密”使用【不同的】密鑰。這玩意兒比較難了解,也比較難想到。當年“非對稱加密”的發明,還被譽為“密碼學”曆史上的一次革命。
由于篇幅有限,對“非對稱加密”這個話題,俺就不展開了。有空的話,再單獨寫一篇掃盲。
看完剛才的定義,很顯然:(從功能角度而言)“非對稱加密”能幹的事情比“對稱加密”要多。這是“非對稱加密”的優點。但是“非對稱加密”的實作,通常需要涉及到“複雜數學問題”。是以,“非對稱加密”的性能通常要差很多(相對于“對稱加密”而言)。
這兩者的優缺點,也影響到了 ssl 協定的設計。
花了好多口水,終于把背景知識說完了。下面正式進入正題。先來說說當初設計 https 是為了滿足哪些需求?
因為是先有 http 再有 https。是以,https 的設計者肯定要考慮到對原有 http 的相容性。
這裡所說的相容性包括很多方面。比如已有的 web 應用要盡可能無縫地遷移到 https;比如對浏覽器廠商而言,改動要盡可能小;......
基于“相容性”方面的考慮,很容易得出如下幾個結論:
1. https 還是要基于 tcp 來傳輸
(如果改為 udp 作傳輸層,無論是 web 服務端還是浏覽器用戶端,都要大改,動靜太大了)
2. 單獨使用一個新的協定,把 http 協定包裹起來
(所謂的“http over ssl”,實際上是在原有的 http 資料外面加了一層 ssl 的封裝。http 協定原有的 get、post 之類的機制,基本上原封不動)
打個比方:如果原來的 http 是塑膠水管,容易被戳破;那麼如今新設計的 https 就像是在原有的塑膠水管之外,再包一層金屬水管。一來,原有的塑膠水管照樣運作;二來,用金屬加強了之後,不容易被戳破。
前面說了,https 相當于是“http over ssl”。
如果 ssl 這個協定在“可擴充性”方面的設計足夠牛逼,那麼它除了能跟 http 搭配,還能夠跟其它的應用層協定搭配。豈不美哉?
現在看來,當初設計 ssl 的人确實比較牛。如今的 ssl/tls 可以跟很多常用的應用層協定(比如:ftp、smtp、pop、telnet)搭配,來強化這些應用層協定的安全性。
接着剛才打的比方:如果把 ssl/tls 視作一根用來加強的金屬管,它不僅可以用來加強輸水的管道,還可以用來加強輸瓦斯的管道。
https 需要做到足夠好的保密性。
說到保密性,首先要能夠對抗嗅探(行話叫 sniffer)。所謂的“嗅探”,通俗而言就是監視你的網絡傳輸流量。如果你使用明文的 http 上網,那麼監視者通過嗅探,就知道你在通路哪些網站的哪些頁面。
嗅探是最低級的攻擊手法。除了嗅探,https 還需要能對抗其它一些稍微進階的攻擊手法——比如“重播攻擊”(後面講協定原理的時候,會再聊)。
在發明 https 之前,由于 http 是明文的,不但容易被嗅探,還容易被篡改。
舉個例子:
比如咱們天朝的網絡營運商(isp)都比較流氓,經常有網友抱怨說通路某網站(本來是沒有廣告的),竟然會跳出很多中國電信的廣告。為啥會這樣捏?因為你的網絡流量需要經過 isp 的線路才能到達公網。如果你使用的是明文的 http,isp 很容易就可以在你通路的頁面中植入廣告。
是以,當初設計 https 的時候,還有一個需求是“確定 http 協定的内容不被篡改”。
在談到 https 的需求時,“真實性”經常被忽略。其實“真實性”的重要程度不亞于前面的“保密性”和“完整性”。
你因為使用網銀,需要通路該網銀的 web 站點。那麼,你如何確定你通路的網站确實是你想通路的網站?(這話有點繞密碼)
有些天真的同學會說:通過看網址裡面的域名,來確定。為啥說這樣的同學是“天真的”?因為 dns 系統本身是不可靠的(尤其是在設計 ssl 的那個年代,連 dnssec 都還沒發明)。由于 dns 的不可靠(存在“域名欺騙”和“域名劫持”),你看到的網址裡面的域名【未必】是真實滴!
是以,https 協定必須有某種機制來確定“真實性”的需求(至于如何確定,後面會細聊)。
再來說最後一個需求——性能。
引入 https 之後,【不能】導緻性能變得太差。否則的話,誰還願意用?
為了確定性能,ssl 的設計者至少要考慮如下幾點:
如何選擇加密算法(“對稱”or“非對稱”)?
如何兼顧 http 采用的“短連接配接”tcp 方式?
(ssl 是在1995年之前開始設計的,那時候的 http 版本還是 1.0,預設使用的是“短連接配接”的 tcp 方式——預設不啟用 keep-alive)
以上就是設計 ssl 協定時,必須兼顧的各種需求。後面聊協定的實作時,俺會拿 ssl 協定的特點跟前面的需求作對照。看看這些需求是如何一一滿足滴。
設計 https 這個協定,有好幾個難點。俺個人認為最大的難點在于“密鑰交換”。
在傳統的密碼學場景中,假如張三要跟李四建立一個加密通訊的管道,雙方事先要約定好使用哪種加密算法?同時也要約定好使用的密鑰是啥?在這個場景中,加密算法的【類型】讓旁人知道,沒太大關系。但是密鑰【千萬不能】讓旁人知道。一旦旁人知道了密鑰,自然就可以破解通訊的密文,得到明文。
好,現在回到 https 的場景。
當你通路某個公網的網站,你的浏覽器和網站的伺服器之間,如果要建立加密通訊,必然要商量好雙方使用啥算法,啥密鑰。——在網絡通訊術語中,這個過程稱之為“握手/handshake”。在握手階段,因為加密方式還沒有協商好,是以握手階段的通訊必定是【明文】滴!既然是明文,自然有可能被第三方偷窺到。然後,還要考慮到雙方之間隔着一個網際網路,什麼樣的偷窺都可能發生。
是以,在握手的過程中,如何做到安全地交換密鑰資訊,而不讓周圍的第三方看到。這就是設計 https 最大的難點。
本文費這麼多口水,來介紹 https 的“需求”和“難點”,為啥捏?因為隻有當你了解這些,後面介紹 ssl/tls 的實作原理時,你才能了解——當初為啥要把協定設計成這個樣子。
原文釋出時間:2015-04-01
本文來自雲栖合作夥伴“linux中國”