原文連接: blog.wangriyu.wang/2018/03-htt…html
SSL(Secure Sockets Layer) 安全套接層,是一種安全協議,經歷了 SSL 1.0、2.0、3.0 版本後發展成了標準安全協議 - TLS(Transport Layer Security) 傳輸層安全性協議。TLS 有 1.0 (RFC 2246)、1.1(RFC 4346)、1.2(RFC 5246)、1.3(RFC 8446) 版本。git
TLS 在實現上分爲 記錄層 和 握手層 兩層,其中握手層又含四個子協議: 握手協議 (handshake protocol)、更改加密規範協議 (change cipher spec protocol)、應用數據協議 (application data protocol) 和警告協議 (alert protocol)web
只需配置瀏覽器和服務器相關設置開啓 TLS,便可實現 HTTPS,TLS 高度解耦,可裝可卸,與上層高級應用層協議相互協做又相互獨立。算法
TLS/SSL 的功能實現主要依賴於三類基本算法:散列函數 Hash、對稱加密和非對稱加密,其利用非對稱加密實現身份認證和密鑰協商,對稱加密算法採用協商的密鑰對數據加密,基於散列函數驗證信息的完整性。windows
TLS 的基本工做方式是,客戶端使用非對稱加密與服務器進行通訊,實現身份驗證並協商對稱加密使用的密鑰,而後對稱加密算法採用協商密鑰對信息以及信息摘要進行加密通訊,不一樣的節點之間採用的對稱密鑰不一樣,從而能夠保證信息只能通訊雙方獲取。瀏覽器
例如,在 HTTPS 協議中,客戶端發出請求,服務端會將公鑰發給客戶端,客戶端驗證事後生成一個密鑰再用公鑰加密後發送給服務端(非對稱加密),雙方會在 TLS 握手過程當中生成一個協商密鑰(對稱密鑰),成功後創建加密鏈接。通訊過程當中客戶端將請求數據用協商密鑰加密後發送,服務端也用協商密鑰解密,響應也用相同的協商密鑰。後續的通訊使用對稱加密是由於對稱加解密快,而握手過程當中非對稱加密能夠保證加密的有效性,可是過程複雜,計算量相對來講也大。緩存
記錄協議負責在傳輸鏈接上交換的全部底層消息,而且能夠配置加密。每一條 TLS 記錄以一個短標頭開始。標頭包含記錄內容的類型 (或子協議)、協議版本和長度。原始消息通過分段 (或者合併)、壓縮、添加認證碼、加密轉爲 TLS 記錄的數據部分。安全
記錄層將信息塊分割成攜帶 2^14 字節 (16KB) 或更小塊的數據的 TLSPlaintext 記錄。服務器
記錄協議傳輸由其餘協議層提交給它的不透明數據緩衝區。若是緩衝區超過記錄的長度限制(2^14),記錄協議會將其切分紅更小的片斷。反過來也是可能的,屬於同一個子協議的小緩衝區也能夠組合成一個單獨的記錄。cookie
struct {
uint8 major, minor;
} ProtocolVersion;
enum {
change_cipher_spec(20),
alert(21),
handshake(22),
application_data(23), (255)
} ContentType;
struct {
ContentType type; // 用於處理封閉片斷的較高級協議
ProtocolVersion version; // 使用的安全協議版本
uint16 length; // TLSPlaintext.fragment 的長度(以字節爲單位),不超過 2^14
opaque fragment[TLSPlaintext.length]; // 透明的應用數據,被視爲獨立的塊,由類型字段指定的較高級協議處理
} TLSPlaintext;
複製代碼
壓縮算法將 TLSPlaintext 結構轉換爲 TLSCompressed 結構。若是定義 CompressionMethod 爲 null 表示不壓縮
struct {
ContentType type; // same as TLSPlaintext.type
ProtocolVersion version; // same as TLSPlaintext.version
uint16 length; // TLSCompressed.fragment 的長度,不超過 2^14 + 1024
opaque fragment[TLSCompressed.length];
} TLSCompressed;
複製代碼
流加密(BulkCipherAlgorithm)將 TLSCompressed.fragment 結構轉換爲流 TLSCiphertext.fragment 結構
stream-ciphered struct {
opaque content[TLSCompressed.length];
opaque MAC[CipherSpec.hash_size];
} GenericStreamCipher;
複製代碼
MAC 產生方法以下:
HMAC_hash(MAC_write_secret, seq_num + TLSCompressed.type + TLSCompressed.version + TLSCompressed.length + TLSCompressed.fragment));
複製代碼
seq_num(記錄的序列號)、hash(SecurityParameters.mac_algorithm 指定的哈希算法)
MAC(Message authentication code) - 消息認證碼
注意,MAC 是在加密以前計算的。流加密加密整個塊,包括 MAC。對於不使用同步向量 (例如 RC4) 的流加密,從一個記錄結尾處的流加密狀態僅用於後續數據包。若是 CipherSuite 是 TLS_NULL_WITH_NULL_NULL,則加密由身份操做 (數據未加密,MAC 大小爲零,暗示不使用 MAC) 組成。TLSCiphertext.length 是 TLSCompressed.length 加上 CipherSpec.hash_size。
塊加密(如 RC2 或 DES),將 TLSCompressed.fragment 結構轉換爲塊 TLSCiphertext.fragment 結構
block-ciphered struct {
opaque content[TLSCompressed.length];
opaque MAC[CipherSpec.hash_size];
uint8 padding[GenericBlockCipher.padding_length];
uint8 padding_length;
} GenericBlockCipher;
複製代碼
padding: 添加的填充將明文長度強制爲塊密碼塊長度的整數倍。填充能夠是長達 255 字節的任何長度,只要知足 TLSCiphertext.length 是塊長度的整數倍。長度大於須要的值能夠阻止基於分析交換信息長度的協議攻擊。填充數據向量中的每一個 uint8 必須填入填充長度值 (即 padding_length)。
padding_length: 填充長度應該使得 GenericBlockCipher 結構的總大小是加密塊長度的倍數。合法值範圍從零到 255(含)。該長度指定 padding_length 字段自己除外的填充字段的長度
加密塊的數據長度(TLSCiphertext.length)是 TLSCompressed.length,CipherSpec.hash_size 和 padding_length 的總和加一
示例: 若是塊長度爲 8 字節,壓縮內容長度(TLSCompressed.length)爲 61 字節,MAC 長度爲 20 字節,則填充前的長度爲 82 字節(padding_length 佔 1 字節)。 所以,爲了使總長度爲塊長度 (8 字節) 的偶數倍,模 8 的填充長度必須等於 6,因此填充長度能夠爲 6,14,22 等。若是填充長度是須要的最小值,好比 6,填充將爲 6 字節,每一個塊都包含值 6。所以,塊加密以前的 GenericBlockCipher 的最後 8 個八位字節將爲 xx 06 06 06 06 06 06 06,其中 xx 是 MAC 的最後一個八位字節。
XX - 06 06 06 06 06 06 - 06 MAC - padding[6] - padding_length 複製代碼
加密和 MAC 功能將 TLSCompressed 結構轉換爲 TLSCiphertext。記錄的 MAC 還包括序列號,以即可以檢測到丟失,額外或重複的消息。
struct {
ContentType type; // same
ProtocolVersion version; // same
uint16 length; // TLSCiphertext.fragment 的長度,不超過 2^14 + 2048
select (CipherSpec.cipher_type) {
case stream: GenericStreamCipher;
case block: GenericBlockCipher;
} fragment; // TLSCompressed.fragment 的加密形式,帶有 MAC
} TLSCiphertext;
複製代碼
注意 這裏提到的都是先 MAC 再加密,是基於 RFC 2246 的方案 (TLS 1.0) 寫的。但新的方案選擇先加密再 MAC,這種替代方案中,首先對明文和填充進行加密,再將結果交給 MAC 算法。這能夠保證主動網絡攻擊者不能操縱任何加密數據。
記錄協議須要一種算法,從握手協議提供的安全性參數生成密鑰、IV 和 MAC secret.
主密鑰 (Master secret): 在鏈接中雙方共享的一個 48 字節的密鑰 客戶隨機數 (client random): 由客戶端提供的 32 字節值 服務器隨機數 (server random): 由服務器提供的 32 字節值
握手是 TLS 協議中最精密複雜的部分。在這個過程當中,通訊雙方協商鏈接參數,而且完成身 份驗證。根據使用的功能的不一樣,整個過程一般須要交換 6~10 條消息。根據配置和支持的協議擴展的不一樣,交換過程可能有許多變種。在使用中常常能夠觀察到如下三種流程:(1) 完整的握手, 對服務器進行身份驗證;(2) 恢復以前的會話採用的簡短握手;(3) 對客戶端和服務器都進行身份驗證的握手。
握手協議消息的標頭信息包含消息類型(1 字節)和長度(3 字節),餘下的信息則取決於消息類型:
struct {
HandshakeType msg_type;
uint24 length;
HandshakeMessage message;
} Handshake;
複製代碼
每個 TLS 鏈接都會以握手開始。若是客戶端此前並未與服務器創建會話,那麼雙方會執行一次完整的握手流程來協商 TLS 會話。握手過程當中,客戶端和服務器將進行如下四個主要步驟:
下面介紹最多見的握手規則,一種不須要驗證客戶端身份但須要驗證服務器身份的握手:
這條消息將客戶端的功能和首選項傳送給服務器。
是將服務器選擇的鏈接參數傳回客戶端。
這個消息的結構與 ClientHello 相似,只是每一個字段只包含一個選項,其中包含服務端的 random_S 參數 (用於後續的密鑰協商)。服務器無需支持客戶端支持的最佳版本。若是服務器不支持與客戶端相同的版本,能夠提供某個其餘版本以期待客戶端可以接受
圖中的 Cipher Suite
是後續密鑰協商和身份驗證要用的加密套件,此處選擇的密鑰交換與簽名算法是 ECDHE_RSA,對稱加密算法是 AES-GCM,後面會講到這個
還有一點默認狀況下 TLS 壓縮都是關閉的,由於 CRIME 攻擊會利用 TLS 壓縮恢復加密認證 cookie,實現會話劫持,並且通常配置 gzip 等內容壓縮後再壓縮 TLS 分片效益不大又額外佔用資源,因此通常都關閉 TLS 壓縮
典型的 Certificate 消息用於攜帶服務器 X.509 證書鏈。 服務器必須保證它發送的證書與選擇的算法套件一致。比方說,公鑰算法與套件中使用的必須匹配。除此之外,一些密鑰交換算法依賴嵌入證書的特定數據,並且要求證書必須以客戶端支持的算法簽名。全部這些都代表服務器須要配置多個證書(每一個證書可能會配備不一樣的證書鏈)。
Certificate 消息是可選的,由於並不是全部套件都使用身份驗證,也並不是全部身份驗證方法都須要證書。更進一步說,雖然消息默認使用 X.509 證書,可是也能夠攜帶其餘形式的標誌;一些套件就依賴 PGP 密鑰
攜帶密鑰交換須要的額外數據。ServerKeyExchange 是可選的,消息內容對於不一樣的協商算法套件會存在差別。部分場景下,好比使用 RSA 算法時,服務器不須要發送此消息。
ServerKeyExchange 僅在服務器證書消息(也就是上述 Certificate 消息)不包含足夠的數據以容許客戶端交換預主密鑰(premaster secret)時才由服務器發送。
好比基於 DH 算法的握手過程當中,須要單獨發送一條 ServerKeyExchange 消息帶上 DH 參數:
代表服務器已經將全部預計的握手消息發送完畢。在此以後,服務器會等待客戶端發送消息。
客戶端驗證證書的合法性,若是驗證經過纔會進行後續通訊,不然根據錯誤狀況不一樣作出提示和操做,合法性驗證內容包括以下:
由 PKI 體系
的內容可知,對端發來的證書籤名是 CA 私鑰加密的,接收到證書後,先讀取證書中的相關的明文信息,採用相同的散列函數計算獲得信息摘要,而後利用對應 CA 的公鑰解密簽名數據,對比證書的信息摘要,若是一致,則能夠確認證書的合法性;而後去查詢證書的吊銷狀況等
合法性驗證經過以後,客戶端計算產生隨機數字的預主密鑰(Pre-master),並用證書公鑰加密,發送給服務器並攜帶客戶端爲密鑰交換提供的全部信息。這個消息受協商的密碼套件的影響,內容隨着不一樣的協商密碼套件而不一樣。
此時客戶端已經獲取所有的計算協商密鑰須要的信息: 兩個明文隨機數 random_C 和 random_S 與本身計算產生的 Pre-master,而後獲得協商密鑰(用於以後的消息加密)
enc_key = PRF(Pre_master, "master secret", random_C + random_S)
複製代碼
圖中使用的是 ECDHE 算法,ClientKeyExchange 傳遞的是 DH 算法的客戶端參數,若是使用的是 RSA 算法則此處應該傳遞加密的預主密鑰
通知服務器後續的通訊都採用協商的通訊密鑰和加密算法進行加密通訊
注意 ChangeCipherSpec 不屬於握手消息,它是另外一種協議,只有一條消息,做爲它的子協議進行實現。
Finished 消息意味着握手已經完成。消息內容將加密,以便雙方能夠安全地交換驗證整個握手完整性所需的數據。
這個消息包含 verify_data 字段,它的值是握手過程當中全部消息的散列值。這些消息在鏈接兩端都按照各自所見的順序排列,並以協商獲得的主密鑰 (enc_key) 計算散列。這個過程是經過一個僞隨機函數(pseudorandom function,PRF)來完成的,這個函數能夠生成任意數量的僞隨機數據。 兩端的計算方法一致,但會使用不一樣的標籤(finished_label):客戶端使用 client finished,而服務器則使用 server finished。
verify_data = PRF(master_secret, finished_label, Hash(handshake_messages))
複製代碼
由於 Finished 消息是加密的,而且它們的完整性由協商 MAC 算法保證,因此主動網絡攻擊者不能改變握手消息並對 vertify_data 的值造假。在 TLS 1.2 版本中,Finished 消息的長度默認是 12 字節(96 位),而且容許密碼套件使用更長的長度。在此以前的版本,除了 SSL 3 使用 36 字節的定長消息,其餘版本都使用 12 字節的定長消息。
服務器用私鑰解密加密的 Pre-master 數據,基於以前交換的兩個明文隨機數 random_C 和 random_S,一樣計算獲得協商密鑰: enc_key = PRF(Pre_master, "master secret", random_C + random_S)
;
一樣計算以前全部收發信息的 hash 值,而後用協商密鑰解密客戶端發送的 verify_data_C,驗證消息正確性;
服務端驗證經過以後,服務器一樣發送 change_cipher_spec 以告知客戶端後續的通訊都採用協商的密鑰與算法進行加密通訊(圖中多了一步 New Session Ticket,此爲會話票證,會在會話恢復中解釋);
服務器也結合全部當前的通訊參數信息生成一段數據 (verify_data_S) 並採用協商密鑰 session secret (enc_key) 與算法加密併發送到客戶端;
客戶端計算全部接收信息的 hash 值,並採用協商密鑰解密 verify_data_S,驗證服務器發送的數據和密鑰,驗證經過則握手完成;
開始使用協商密鑰與算法進行加密通訊。
HTTPS 經過 TLS 層和證書機制提供了內容加密、身份認證和數據完整性三大功能。加密過程當中,須要用到非對稱密鑰交換和對稱內容加密兩大算法。
對稱內容加密強度很是高,加解密速度也很快,只是沒法安全地生成和保管密鑰。在 TLS 協議中,最後的應用數據都是通過對稱加密後傳輸的,傳輸中所使用的對稱協商密鑰(上文中的 enc_key),則是在握手階段經過非對稱密鑰交換而來。常見的 AES-GCM、ChaCha20-Poly1305,都是對稱加密算法。
非對稱密鑰交換能在不安全的數據通道中,產生只有通訊雙方纔知道的對稱加密密鑰。目前最經常使用的密鑰交換算法有 RSA 和 ECDHE。
RSA 歷史悠久,支持度好,但不支持 完美前向安全 - PFS(Perfect Forward Secrecy);而 ECDHE 是使用了 ECC(橢圓曲線)的 DH(Diffie-Hellman)算法,計算速度快,且支持 PFS。
在 PKI 體系
一節中說明了僅有非對稱密鑰交換仍是沒法抵禦 MITM 攻擊的,因此須要引入了 PKI 體系的證書來進行身份驗證,其中服務端非對稱加密產生的公鑰會放在證書中傳給客戶端。
在 RSA 密鑰交換中,瀏覽器使用證書提供的 RSA 公鑰加密相關信息,若是服務端能解密,意味着服務端擁有與公鑰對應的私鑰,同時也能算出對稱加密所需密鑰。密鑰交換和服務端認證合併在一塊兒。
在 ECDH 密鑰交換中,服務端使用私鑰 (RSA 或 ECDSA) 對相關信息進行簽名,若是瀏覽器能用證書公鑰驗證簽名,就說明服務端確實擁有對應私鑰,從而完成了服務端認證。密鑰交換則是各自發送 DH 參數完成的,密鑰交換和服務端認證是徹底分開的。
可用於 ECDHE 數字簽名的算法主要有 RSA 和 ECDSA - 橢圓曲線數字簽名算法,也就是目前密鑰交換 + 簽名有三種主流選擇:
RSA
- RSA 密鑰交換(無需簽名)ECDHE_RSA
- ECDHE 密鑰交換、RSA 簽名ECDHE_ECDSA
- ECDHE 密鑰交換、ECDSA 簽名好比個人網站使用的加密套件是 ECDHE_RSA,能夠看到數字簽名算法是 sha256 哈希加 RSA 加密,在 PKI 體系
一節中講了簽名是服務器信息摘要的哈希值加密生成的
內置 ECDSA 公鑰的證書通常被稱之爲 ECC 證書,內置 RSA 公鑰的證書就是 RSA 證書。由於 256 位 ECC Key 在安全性上等同於 3072 位 RSA Key,因此 ECC 證書體積比 RSA 證書小,並且 ECC 運算速度更快,ECDHE 密鑰交換 + ECDSA 數字簽名是目前最好的加密套件
以上內容來自本文: 開始使用 ECC 證書
關於 ECC 證書的更多細節可見文檔: ECC Cipher Suites for TLS - RFC4492
使用 RSA 進行密鑰交換的握手過程與前面說明的基本一致,只是沒有 ServerKeyExchange 消息,其中協商密鑰涉及到三個參數 (客戶端隨機數 random_C、服務端隨機數 random_S、預主密鑰 Premaster secret), 其中前兩個隨機數和協商使用的算法是明文的很容易獲取,最後一個 Premaster secret 會用服務器提供的公鑰加密後傳輸給服務器 (密鑰交換),若是這個預主密鑰被截取並破解則協商密鑰也能夠被破解。
RSA 算法的細節見: wiki 和 RSA算法原理(二)- 阮一峯
RSA 的算法核心思想是利用了極大整數 因數分解 的計算複雜性
而使用 DH(Diffie-Hellman) 算法 進行密鑰交換,雙方只要交換各自的 DH 參數(在 ServerKeyExchange 發送 Server params,在 ClientKeyExchange 發送 Client params),不須要傳遞 Premaster secret,就能夠各自算出這個預主密鑰
DH 的握手過程以下,大體過程與 RSA 相似,圖中只表達如何生成預主密鑰:
服務器經過私鑰將客戶端隨機數 random_C,服務端隨機數 random_S,服務端 DH 參數 Server params 簽名生成 signature,而後在 ServerKeyExchange 消息中發送服務端 DH 參數和該簽名;
客戶端收到後用服務器給的公鑰解密驗證簽名,並在 ClientKeyExchange 消息中發送客戶端 DH 參數 Client params;
服務端收到後,雙方都有這兩個參數,再各自使用這兩個參數生成預主密鑰 Premaster secret,以後的協商密鑰等步驟與 RSA 基本一致。
基於 RSA 算法與 DH 算法的握手最大的區別就在於密鑰交換與身份認證。前者客戶端使用公鑰加密預主密鑰併發送給服務端完成密鑰交換,服務端利用私鑰解密完成身份認證。後者利用各自發送的 DH 參數完成密鑰交換,服務器私鑰簽名數據,客戶端公鑰驗簽完成身份認證。
關於 DH 算法如何生成預主密鑰,推薦看下 Wiki 和 Ephemeral Diffie-Hellman handshake
其核心思想是利用了 離散對數問題 的計算複雜性
原根:假設一個整數 g 對於質數 P 來講是原根,那麼 g^i mod P (1 ≦ i < P) 的結果各不相同,且其結果按必定順序排列後是 1 到 P-1 的全部整數,例子
離散對數:若是對於一個整數 n 和質數 P 的一個原根 g,能夠找到一個惟一的指數 i,使得 n = g^i mod P (0 ≦ i < P),那麼指數 i 稱爲 n 的以 g 爲基數的模 P 的離散對數
Diffie-Hellman 算法的有效性依賴於計算離散對數的難度,其含義是:當已知大素數 P 和它的一個原根 g 後,對給定的 n,要計算 i,被認爲是很困難的,而給定 i 計算 n 卻相對容易
算法過程能夠抽象成下圖:
雙方預先商定好了一對 P g 值 (公開的),而 Alice 有一個私密數 a(非公開,對應一個私鑰),Bob 有一個私密數 b(非公開,對應一個私鑰)
Alice 計算 A = g^a mod P,並把 A(公開,對應一個公鑰) 發給 Bob
Bob 計算 B = g^b mod P,並把 B(公開,對應一個公鑰) 發給 Alice
雙方計算出共享密鑰,K = B^a mod P = A^b mod P (= g^ab mod P)
對於 Alice 和 Bob 來講經過對方發過來的公鑰參數和本身手中的私鑰能夠獲得最終相同的密鑰
而第三方最多知道 P g A B,想獲得私鑰和最後的密鑰很困難,固然前提是 a b P 足夠大 (RFC3526 文檔中有幾個經常使用的大素數可供使用),不然暴力破解也有可能試出答案,至於 g 通常取個較小值就能夠
以下幾張圖是實際 DH 握手發送的內容:
能夠看到雙方發給對方的參數中攜帶了一個公鑰值,對應上述的 A 和 B
並且實際用的加密套件是 橢圓曲線 DH 密鑰交換 (ECDH),利用由橢圓曲線加密創建公鑰與私鑰對能夠更進一步增強 DH 的安全性,由於目前解決橢圓曲線離散對數問題要比因式分解困難的多,並且 ECC 使用的密鑰長度比 RSA 密鑰短得多(目前 RSA 密鑰須要 2048 位以上才能保證安全,而 ECC 密鑰 256 位就足夠)
關於 橢圓曲線密碼學 - ECC,推薦看下 A Primer on Elliptic Curve Cryptography - 原文 - 譯文
儘管能夠選擇對任意一端進行身份驗證,但人們幾乎都啓用了對服務器的身份驗證。若是服務器選擇的套件不是匿名的,那麼就須要在 Certificate 消息中跟上本身的證書。
相比之下,服務器經過發送 CertificateRequest 消息請求對客戶端進行身份驗證。消息中列出全部可接受的客戶端證書。做爲響應,客戶端發送本身的 Certificate 消息(使用與服務器發送證書相同的格式),並附上證書。此後,客戶端發送 CertificateVerify 消息,證實本身擁有對應的私鑰。
只有已通過身份驗證的服務器才被容許請求客戶端身份驗證。基於這個緣由,這個選項也被稱爲相互身份驗證(mutual authentication)。
在 ServerHello 的過程當中發出,請求對客戶端進行身份驗證,並將其接受的證書的公鑰和簽名算法傳送給客戶端。
它也能夠選擇發送一份本身接受的證書頒發機構列表,這些機構都用其可分辨名稱來表示:
struct {
ClientCertificateType certificate_types;
SignatureAndHashAlgorithm supported_signature_algorithms;
DistinguishedName certificate_authorities;
} CertificateRequest;
複製代碼
在 ClientKeyExchange 的過程當中發出,證實本身擁有的私鑰與以前發送的客戶端證書中的公鑰匹配。消息中包含一條到這一步爲止的全部握手消息的簽名:
struct {
Signature handshake_messages_signature;
} CertificateVerify;
複製代碼
最初的會話恢復機制是,在一次完整協商的鏈接斷開時,客戶端和服務器都會將會話的安全參數保存一段時間。但願使用會話恢復的服務器爲會話指定惟一的標識,稱爲會話 ID(Session ID)。服務器在 ServerHello 消息中將會話 ID 發回客戶端。
但願恢復早先會話的客戶端將適當的 Session ID 放入 ClientHello 消息,而後提交。服務器若是贊成恢復會話,就將相同的 Session ID 放入 ServerHello 消息返回,接着使用以前協商的主密鑰生成一套新的密鑰,再切換到加密模式,發送 Finished 消息。 客戶端收到會話已恢復的消息之後,也進行相同的操做。這樣的結果是握手只須要一次網絡往返。
Session ID 由服務器端支持,協議中的標準字段,所以基本全部服務器都支持,服務器端保存會話 ID 以及協商的通訊信息,佔用服務器資源較多。
用來替代服務器會話緩存和恢復的方案是使用會話票證(Session ticket)。使用這種方式,除了全部的狀態都保存在客戶端(與 HTTP Cookie 的原理相似)以外,其消息流與服務器會話緩存是同樣的。
其思想是服務器取出它的全部會話數據(狀態)並進行加密 (密鑰只有服務器知道),再以票證的方式發回客戶端。在接下來的鏈接中,客戶端恢復會話時在 ClientHello 的擴展字段 session_ticket 中攜帶加密信息將票證提交回服務器,由服務器檢查票證的完整性,解密其內容,再使用其中的信息恢復會話。
這種方法有可能使擴展服務器集羣更爲簡單,由於若是不使用這種方式,就須要在服務集羣的各個節點之間同步會話。 Session ticket 須要服務器和客戶端都支持,屬於一個擴展字段,佔用服務器資源不多。
警告 會話票證破壞了 TLS 安全模型。它使用票證密鑰加密的會話狀態並將其暴露在線路上。有些實現中的票證密鑰可能會比鏈接使用的密碼要弱。若是票證密鑰被暴露,就能夠解密鏈接上的所有數據。所以,使用會話票證時,票證密鑰須要頻繁輪換。