知乎都全站 HTTPS 好久了, 你還好意思不懂 HTTPS?

gjd2kfojstf 8年前發布 | 62K 次閱讀 SSL協議 加密解密 網絡技術 HTTPS

推廣 HTTPS 的道路從來都不是一帆風順的,國外的互聯網大頭貌似都在飛快地推行著而且基本都已經實現全站了,國內推廣的速度反而像蝸牛一樣。BAT 也就阿里上了全站 HTTPS,百度也開始逐步邁向 HTTPS 的行列,像百度圖片還沒有。我也就不噴國內某大型社交網站登陸賬號用的是 HTTP + GET 的方式請求了,雖然加了校驗,但是還是有風險。

上全站 HTTPS 的流程大概是這樣的:

買證書啊

中國的一個叫 WoSign 的 CA 之前給一個 schrauger.github.com 生成了一個 *.github.com 的 SSL,然后還有一個月內生成了幾百個相同序列號的證書。Firefox 腦袋一拍,決定從 2016 年 10月份把它從信任 CA 列表中除名。對 WoSign 感興趣?這里: CA:WoSign Issues ,你也可以點上面那個 github 的地址,第一篇就是:The story of how WoSign gave me an SSL certificate for GitHub.com。

所以你需要考慮到底是用國內的還是國外的。就安全性來說當然是 GeoTrust 是最靠譜的,但是貴呀。如果你的企業有一定的背景,說不定還不讓用國外的產品。

So... 如果你網管不小心配錯了證書,但是你又開了 HTTPS 的端口,會這樣:

或者這樣:

證書夠裝逼才行

說到證書,你會發現它有很多種類型的,最裝逼的當然是 推ter 這樣的啦:

這類證書叫做:EV 證書。如果你公司名字比較長可能會比較蛋疼,譬如會變成這樣:

在最新版的 Chrome 下已經不顯示名字了,只有 Safari 才顯示。Chrome 下和普通證書顯示一樣,只有一個綠色的鎖。

這個證書麻煩在于不支持通配,譬如只能 “推ter.com” 或者 “www.推ter.com” ,而不能 “*.推ter.com”,維護成本特別高。

所以大家一般都會選擇支持 “*.推ter.com” 的 wildcard 證書。或者同時支持 “taobao.com” 和 “alipay.com” 這樣的 SAN 證書。

上全量 CDN 的 HTTPS 啊

買證書的錢其實還好,服務端的加密解密消耗的服務器其實也還好。最大的頭其實來自 CDN,動態內容上了 HTTPS,所有靜態內容也要跟著上,都是錢啊貴著呢!去看看 HTTPS 和 HTTP 的價格,差好幾倍啊。

不然你的頁面會變成這樣,這特么不是和 HTTP 一毛一樣么!甚至還變差了!

SNI 支持

默認情況下,在客戶端和服務端建立好連接之后。服務端會把默認的 SSL 證書發過去給客戶做 SSL 校驗。但是隨著服務器性能逐漸變強,一臺服務器會部署多個 SSL 證書服務多個站點(CDN 是最典型的)。服務端需要客戶端先告知正準備訪問的網站域名(Header 中 Host 字段),然后服務端才能發送正確的 SSL 證書信息和客戶端來 SSL 握手。

如果在上之前沒有調研過這個東西,上線之后可能會收到一堆 Windows XP 的用戶的反饋。國內不乏有大量古董級用戶,用著 windows XP + IE6。如果你上了 HTTPS 他們將永遠上不去你的網站了。因為 Windows XP 不支持 SNI。如果你只有一個證書,同時只有一個入口,那么你的動態請求就不會有問題。但是像 CDN 這類第三方服務,人家不可能只為你服務(好吧只要你有錢你也是可以的)。

SSL 加解密

軟件扛 HTTPS 流量現在主要用 Haproxy 或者 Nginx。如果配置正確加上合理的優化,一臺 24 核的 Haproxy 是可以輕松扛下 10,000 qps 的量。

關于 SSL 的版本,有:SSL 1.0、SSL 2.0、SSL 3.0、 TLS 1.0、TLS 1.1、TLS 1.2。前面三個協議因為發現有漏洞,已經廢棄了。Haproxy 和 Nginx 的 SSL Protocol 默認都是 TLS 的三個。

------------

好了文章終于可以進入正文了!說到 HTTPS,涉及 2 個概念。

  • 怎么保證我和真實服務端的通訊是安全的。

  • 怎么證明我的拿到的請求是真實服務端發我的。

HTTPS 怎么保證通訊安全

怎么保證我和真實服務端的通訊是安全的呢?這個問題就好像你和你女朋友想聊一些很羞羞的話題不希望別人知道。其實很簡單。這個時候就需要用到非對稱加密算法了,簡單來說就是一個公鑰和一個私鑰:

  • 公鑰加密的內容私鑰可以解密
  • 私鑰解密的內容公鑰可以解密
  • 公鑰是公開給每個人的,私鑰是只有服務端自己持有

你拿著私鑰,然后把公鑰遞給你的女朋友。你們每次發送之前都做一次加密就完事了。

但是你會想到另外一個問題:怎么證明和我聊天的就是我的女朋友呢,或者說你的女朋友怎么知道正在聊天的那個就是你呢?說不定在第一次遞交公鑰的時候就已經被人冒充拿走了!這怎么行!

這就是第二個問題:怎么證明我的拿到的請求是真實服務端發我的。聰明的你想到一個辦法,你找了一個第三方公正。你和公正說:公正,你也生成一對密鑰吧。然后你用你的私鑰把我的公鑰給加密了。

然后你把這個被公正加密過的公鑰給了你女朋友,你女朋友會嘗試用公正的公鑰(公鑰都是公開的)去解密,發現解密成功,說明這個公鑰真的是你的。就可以安心的聊羞羞話題了。

所以流程是:服務端(你自己)生成一對密鑰,找 CA (公正)讓它用私鑰把你的公鑰加密,然后客戶(你女朋友)在訪問你的時候嘗試用 CA 的公鑰解密你的公鑰,解密成功表示你是可信任的。

聰明的你又想到一個問題,如果 CA 的公鑰也被冒充了怎么辦?感覺進入死循環了。所以,所有瀏覽器都會內置一系列 CA 公鑰。這樣就完全隔離了網絡了。但是這樣也有缺陷,會導致更新 CA 不及時,證書不能實時撤銷的問題。

而我們經常說到的 GeoTrust,以及國內被黑的很慘的 WoSign 就是 CA 機構。同樣,一旦他們的私鑰泄漏了,這就意味著這家公司可以做破產清算了,同時很多互聯網公司都可能會出現數據泄漏或者賬號被竊的風險。

HTTPS 通訊到底用了多少種算法

非對稱加密算法無非是互聯網安全通信最重要的協議之一,奠定了整個互聯網安全架構。但是 RSA 算法本身計算量特別大,如果把所有數據都通過 RSA 加密解密會特別消耗計算能力,所以 HTTPS 并不是一直都是用非對稱算法的:

  • HTTPS 在做 SSL 握手的時候是非對稱加密
  • 握手成功之后使用對稱加密傳輸數據
  • 同時還用到 Hash 算法校驗數據的一致性

所以前面的舉例其實并不妥當,應該是你女朋友和你握手完了之后協商了一個對稱密鑰,然后用這個對稱密鑰加密通訊的。

HTTPS 握手流程

所有鋪墊都已說明,那么,我們來說 SSL 到底是怎么建立的,我們現在只討論基于 RSA 的加密方式。

所有的包都被封裝為 Record Layer 結構體里面,可以是一個,也可以是多個,這樣可以減少包的數量,里面包括:

  • Content Type:表示這是什么類型的包,握手階段都是 Handshake
  • Version:表示是用什么 SSL 協議,較新的瀏覽器都會使用 TLS 1.2
  • Length:包的內容的長度,指的是 Fragment 的長度,不是整個包的長度。
  • Fragment:和包的類型相關,譬如在握手階段就是 Handshake Protocol 的結構體,連接連接后的傳輸過程,這里就是 Encrypted Application Data 的結構體。

Client Hello

在客戶端和服務端完成了 TCP 握手建立了連接之后,客戶端會發送 Client Hello 包,其中包括 4 個重要的字段需要說明一下:

  • Random:由時間戳和 28 bytes 的隨機數組成,將用于后面生成 Master Secret。
  • SessionID:用來標記是否復用之前的連接。
  • Cipher Suites:用于告知客戶端自己支持的 Cipher Suites。可以在服務器上運行
openssl ciphers -V

查看自己電腦支持的 Cipher Suites。

譬如

0xC0,0x30 - ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD

表示用 RSA 算法驗證證書,用 AES256 加密數據,用 SHA384 驗證數據一致性。

  • Server Name(擴展):告知服務端正在訪問的是什么域名,因為 SNI 是后面才補充進去 RFC 的,所以放在了擴展字段里面。注意如果你的客戶端不支持 SNI,將不會帶上這個字段,這個時候服務器就會傳回默認的 SSL 證書了。

Server Hello

服務端收到客戶端發來的 Client Hello 之后,會傳回 Server Hello 包,其中包括:

  • Random:由時間戳和 28 bytes 的隨機數組成,將用于后面生成 Master Secret。
  • SessionID:一個 32 bytes 的隨機數,如果下次客戶端想復用這個連接,在 Client Hello 中帶上即可。
  • Cipher Suite:服務端會根據客戶端傳來的 Cipher Suites 從中選擇一個用于加密。

Certificate

在服務端發送完 Server Hello 之后,會馬上繼續發一個 2464 bytes 大小的包,里面包括了服務端的公鑰。

Server key Exchange Message & Server Hello Done

如果發送完 Certificate 之后還需要補充一些其他的信息,譬如加密算法相關的,會額外補充一個 Server key Exchange 的包,最后會統一發送一個 Server Hello Done 的包表示傳輸結束。

Verify Certificate and Signatures

客戶端收到服務端發來的證書文件之后,必須檢驗:

  • 證書的 Common Name 是否符合我們訪問的域名,如果不符合,會彈出警告框讓用戶選擇是否繼續
  • 證書的時間,不能早于證書上的 “not before”,也不能晚于 “not after”
  • 使用 CA 的公鑰驗證服務端公鑰是未被篡改的,同樣,如果發現 CA 校驗不正確,瀏覽器也會彈出警告

驗證過程涉及到 RSA 算法,如果感興趣可以看阮一峰的這篇文章: RSA算法原理(一) - 阮一峰的網絡日志

Client Key Exchange Message

客戶端在驗證服務端發來的證書是可靠的之后,會生成一個 48 bytes 的隨機數,我們稱之為 Pre-Master Secret。然后使用服務端的公鑰對這個 Pre-Master Secret 加密,傳回服務端。不同的加密方法可能會加上位數填充等手段增加其安全性。

Change Cipher Spec

這是客戶端發送的最后一個明文包,告訴服務端我們之后所有的請求都會通過協商好的加密方法進行通訊。同樣,服務端也會傳回一個 Change Cipher Spec 告知客戶端收到了。這里有一點注意,這個 Change Cipher Spec 是可以和前面的 Client Key Exchange Message,或者其他包共用同一個 TCP 包的。SSL Record Layer 里面也允許這樣做,而且大部分瀏覽器也是這樣做的,可以有效減少 TCP 包的包量。

Master Secret

雙方并不是只依賴 Pre-Master Secret 來加密解密傳輸數據,最后會生成一個 Master Secret 用來加解密,函數為:

master_secret = PRF(pre_master_secret, 
                    "master secret", 
                    ClientHello.random + ServerHello.random)
[0..47];

這里終于用到了最開始提到的兩個 random。取前面 48 bytes,后面全部截斷。

剩下的就是用對稱算法對內容進行加密了,部分算法涉及到生成多個 key pair,在此就不展開了,想了解可以看這里: The TLS Protocol Version 1.0

同樣在加密之后,會對內容做一次 HASH,譬如這樣:

verify_data = PRF(master_secret, "client finished", MD5(handshake_messages) + SHA-1(handshake_messages) ) 
[12]

這里假設使用的是 MD5 的校驗方法。

Application Layer

恭喜你,你終于完成了 SSL 握手,進入了應用層。

匯總

最后我們來看一看抓包的截圖

后續

如果大家對 HTTPS 希望了解的更深,可以看看這篇文章: The First Few Milliseconds of an HTTPS Connection 非常詳細的介紹了整個過程。文章結尾還有一個小程序描述整個 SSL 握手的過程。

-------

參考文獻:

  1. The TLS Protocol Version 1.0
  2. Transport Layer Security (TLS) Extensions
  3. The First Few Milliseconds of an HTTPS Connection
  4. Understanding SSL\HTTPS
  5. HTTPS and the TLS handshake protocol.
  6. RSA算法原理(一) - 阮一峰的網絡日志
  7. RSA算法原理(二) - 阮一峰的網絡日志

 

來自:https://zhuanlan.zhihu.com/p/25030869

 

 本文由用戶 gjd2kfojstf 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!