TLS 握手優化詳解

2021-09-14 02:37:54 字數 3946 閱讀 4484

隨著 http/2 的逐漸普及,以及國內網路環境越來越糟糕(運營商劫持和篡改),https 已經開始成為主流。https 在 tcp 和 http 之間增加了 tls(transport layer security,傳輸層安全),提供了內容加密、身份認證和資料完整性三大功能,同時也給 web 效能優化帶來新的挑戰。

tls 的前身是 ssl(secure sockets layer,安全套接字層),由網景公司開發,後來被 ietf 標準化並改名。通常沒有特別說明時,ssl 和 tls 指的是同乙個協議,不做嚴格區分。

在傳輸應用資料之前,客戶端必須與服務端協商金鑰、加密演算法等資訊,服務端還要把自己的證書發給客戶端表明其身份,這些環節構成 tls 握手過程,如下圖所示:

可以看到,假設服務端和客戶端之間單次傳輸耗時 28ms,那麼客戶端需要等到 168ms 之後才能開始傳送 http 請求報文,這還沒把客戶端和服務端處理時間算進去。光是 tls 握手就需要消耗兩個 rtt(round-trip time,往返時間),這就是造成 https 更慢的主要原因。當然,https 要求資料加密傳輸,加解密相比 http 也會帶來額外的開銷,不過對稱加密本來就很快,加上硬體效能越來越好,所以這部分開銷還好。

通過 wireshark 抓包可以清楚地看到完整 tls 握手過程所需的兩個 rtt,如下圖:

false start 有搶跑的意思,意味著不按規則行事。tls false start 是指客戶端在傳送 change cipher spec finished 同時傳送應用資料(如 http 請求),服務端在 tls 握手完成時直接返回應用資料(如 http 響應)。這樣,應用資料的傳送實際上並未等到握手全部完成,故謂之搶跑。這個過程如下圖所示:

可以看到,啟用 false start 之後,tls 階段只需要一次 rtt 就可以開始傳輸應用資料。false start 相當於客戶端提前傳送加密後的應用資料,不需要修改 tls 協議,目前大部分瀏覽器預設都會啟用,但也有一些前提條件:

使用支援前向安全性(forward secrecy)的加密演算法。false start 在尚未完成握手時就傳送了應用資料,forward secrecy 可以提高安全性;

通過 wireshark 抓包可以清楚地看到 false start 帶來的好處(服務端的 changecipherspec 出現在 158 號包中,但在之前的 155 號包中,客戶端已經發出了請求,相當於 tls 握手只消耗了乙個 rtt):

tls 的身份認證是通過證書信任鏈完成的,瀏覽器從站點證書開始遞迴校驗父證書,直至出現信任的根證書(根證書列表一般內置於作業系統,firefox 自己維護)。站點證書是在 tls 握手階段,由服務端傳送的。

certificate-chain

配置服務端證書鏈時,有兩點需要注意:1)證書是在握手期間傳送的,由於 tcp 初始擁塞視窗的存在,如果證書太長可能會產生額外的往返開銷;2)如果證書沒包含中間證書,大部分瀏覽器可以正常工作,但會暫停驗證並根據子證書指定的父證書 url 自己獲取中間證書。這個過程會產生額外的 dns 解析、建立 tcp 連線等開銷,非常影響效能。

配置證書鏈的最佳實踐是只包含站點證書和中間證書,不要包含根證書,也不要漏掉中間證書。大部分證書鏈都是「站點證書 - 中間證書 - 根證書」這樣**,這時服務端只需要傳送前兩個證書即可。但也有的證書鏈有四級,那就需要傳送站點證書外加兩個中間證書了。

通過 wireshark 可以檢視服務端傳送的證書鏈情況,如下圖。可以看到本站傳送了兩個證書,共 2270 位元組,被分成 2 個 tcp 段來傳輸。這已經算小的了,理想的證書鏈應該控制在 3kb 以內。

如果需要進一步減小證書大小,可以選擇 ecc(elliptic curve cryptography,橢圓曲線密碼學)證書。256 位的 ecc key 等同於 3072 位的 rsa key,在確保安全性的同時,體積大幅減小。下面是乙個對比:

對稱加密 key 長度

rsa key 長度

ecc key 長度

801024

160112

2048

224128

3072

256192

7680

384256

15360

521如果證書提供商支援 ecc 證書,使用以下命令生成 csr(certificate signing request,證書簽名請求)檔案並提交給提供商,就可以獲得 ecc 證書:

openssl ecparam -genkey -name secp256r1 | openssl ec -out ecc.key

openssl req -new -key ecc.key -out ecc.csr

以上命令中可以選擇的演算法有 secp256r1 和 secp384r1,secp521r1 已被 chrome 和 firefox 拋棄。

ecc 證書這麼好,為什麼沒有普及呢?最主要的原因是它的支援情況並不好。例如 windows xp 不支援,導致使用 ecc 證書的**在 windows xp 上只有 firefox 能訪問(firefox 證書那一套完全自己實現,不依賴作業系統)。另外,android 平台也只有 android 4+ 才支援 ecc 證書。所以,確定使用 ecc 證書前需要明確使用者系統分布情況。

另外乙個提高 tls 握手效率的機制是會話復用。會話復用的原理很簡單,將第一次握手辛辛苦苦算出來的對稱金鑰存起來,後續請求中直接使用。這樣可以節省證書傳送等開銷,也可以將 tls 握手所需 rtt 減少到乙個,如下圖所示:

可以看到會話復用機制生效時,雙方幾乎不怎麼交換資料就協商好金鑰了,這是怎麼做到的呢?

session identifier

session identifier(會話識別符號),是 tls 握手中生成的 session id。服務端可以將 session id 協商後的資訊存起來,瀏覽器也可以儲存 session id,並在後續的 clienthello 握手中帶上它,如果服務端能找到與之匹配的資訊,就可以完成一次快速握手。

session ticket

session identifier 機制有一些弊端,例如:1)負載均衡中,多機之間往往沒有同步 session 資訊,如果客戶端兩次請求沒有落在同一臺機器上就無法找到匹配的資訊;2)服務端儲存 session id 對應的資訊不好控制失效時間,太短起不到作用,太長又占用服務端大量資源。

而 session ticket(會話記錄單)可以解決這些問題,session ticket 是用只有服務端知道的安全金鑰加密過的會話資訊,最終儲存在瀏覽器端。瀏覽器如果在 clienthello 時帶上了 session ticket,只要伺服器能成功解密就可以完成快速握手。

配置 session ticket 策略後,通過 wireshark 可以看到服務端傳送 ticket 的過程:

以下是 session resumption 機制生效時的握手情況,可以看到沒有傳送證書等環節:

TLS握手過程

客戶端與伺服器商議通訊金鑰的過程稱為tls握手,在握手階段,通訊內容雖然都是明文,但要保證最終商量的金鑰只有客戶端和伺服器知道,其他中間節點無從得知。rsa握手過程說明 生成master secret 以及從master secret中得到session key mastersecret gener...

TLS協議握手過程分析

比如說bob有乙個 bob.cn,bob生成了一對公私鑰,其把個人身份及公鑰傳送給ca登記機構,ca登記機構驗證bob的身份,比如是個dv證書,就看證書所對應的網域名稱是不是你的,網域名稱是不是指向你的伺服器。登記機構驗證通過之後,就會把證書簽名申請傳送給ca機構,ca機構用其私鑰簽名之後,頒發證書...

TLS握手秘鑰套件分析

1 為了弄清楚tls1.3的內部結構,覺得有必要將tls的整個結構從新整理一遍,方便後續在做握手協議的形式化分析的時候能夠不遺漏每個加密和認證的的環節。tls1.3不 在協議內容上還是效能上都較之前的tls1.2版本有較大的改變,這裡首先概括性的表徵一下存在的差異 更換了新的密碼套件,舊的密碼套件不...