SSL介紹:
安全套接字(Secure Socket Layer,SSL)協議是Web瀏覽器與Web服務器之間安全交換信息的協議,提供兩個基本的安全服務:鑒別與保密。
SSL是Netscape於1994年開發的,后來成為了世界上最著名的web安全機制,所有主要的瀏覽器都支持SSL協議
目前有三個版本:2、3、3.1,最常用的是第3版,是1995年發布的。
SSL協議的三個特性
① 保密:在握手協議中定義了會話密鑰后,所有的消息都被加密。
② 鑒別:可選的客戶端認證,和強制的服務器端認證。
③ 完整性:傳送的消息包括消息完整性檢查(使用MAC)。
SSL的位置
SSL介於應用層和TCP層之間。應用層數據不再直接傳遞給傳輸層,而是傳遞給SSL層,SSL層對從應用層收到的數據進行加密,並增加自己的SSL頭。
SSL的工作原理
握手協議(Handshake protocol)
記錄協議(Record protocol)
警報協議(Alert protocol)
1、握手協議
握手協議是客戶機和服務器用SSL連接通信時使用的第一個子協議,握手協議包括客戶機與服務器之間的一系列消息。SSL中最復雜的協議就是握手協議。該協議允許服務器和客戶機相互驗證,協商加密和MAC算法以及保密密鑰,用來保護在SSL記錄中發送的數據。握手協議是在應用程序的數據傳輸之前使用的。
每個握手協議包含以下3個字段
(1)Type:表示10種消息類型之一
(2)Length:表示消息長度字節數
(3)Content:與消息相關的參數
握手協議的4個階段

1.1建立安全能力
SSL握手的第一階段啟動邏輯連接,建立這個連接的安全能力。首先客戶機向服務器發出client hello消息並等待服務器響應,隨后服務器向客戶機返回server hello消息,對client hello消息中的信息進行確認。
Client hello消息包括Version,Random,Session id,Cipher suite,Compression method等信息。

ClientHello 客戶發送CilentHello信息,包含如下內容:
(1)客戶端可以支持的SSL最高版本號
(2)一個用於生成主秘密的32字節的隨機數。(等會介紹主秘密是什么)
(3)一個確定會話的會話ID。
(4)一個客戶端可以支持的密碼套件列表。
密碼套件格式:每個套件都以“SSL”開頭,緊跟着的是密鑰交換算法。用“With”這個詞把密鑰交換算法、加密算法、散列算法分開,例如:SSL_DHE_RSA_WITH_DES_CBC_SHA,表示把DHE_RSA(帶有RSA數字簽名的暫時Diffie-HellMan)定義為密鑰交換算法;把DES_CBC定義為加密算法;把SHA定義為散列算法。
(5)一個客戶端可以支持的壓縮算法列表。
ServerHello 服務器用ServerHello信息應答客戶,包括下列內容
(1)一個SSL版本號。取客戶端支持的最高版本號和服務端支持的最高版本號中的較低者。
(2)一個用於生成主秘密的32字節的隨機數。(客戶端一個、服務端一個)
(3)會話ID
(4)從客戶端的密碼套件列表中選擇的一個密碼套件
(5)從客戶端的壓縮方法的列表中選擇的壓縮方法
這個階段之后,客戶端服務端知道了下列內容:
(1)SSL版本
(2)密鑰交換、信息驗證和加密算法
(3)壓縮方法
(4)有關密鑰生成的兩個隨機數。
1.2 服務器鑒別與密鑰交換
服務器啟動SSL握手第2階段,是本階段所有消息的唯一發送方,客戶機是所有消息的唯一接收方。該階段分為4步:
(a)證書:服務器將數字證書和到根CA整個鏈發給客戶端,使客戶端能用服務器證書中的服務器公鑰認證服務器。
(b)服務器密鑰交換(可選):這里視密鑰交換算法而定
(c)證書請求:服務端可能會要求客戶自身進行驗證。
(d)服務器握手完成:第二階段的結束,第三階段開始的信號

這里重點介紹一下服務端的驗證和密鑰交換。這個階段的前面的(a)證書 和(b)服務器密鑰交換是基於密鑰交換方法的。而在SSL中密鑰交換算法有6種:無效(沒有密鑰交換)、RSA、匿名Diffie-Hellman、暫時Diffie-Hellman、固定Diffie-Hellman、Fortezza。
在階段1過程客戶端與服務端協商的過程中已經確定使哪種密鑰交換算法。
如果協商過程中確定使用RSA交換密鑰,那么過程如下圖:

這個方法中,服務器在它的第一個信息中,發送了RSA加密/解密公鑰證書。不過,因為預備主秘密是由客戶端在下一個階段生成並發送的,所以第二個信息是空的。注意,公鑰證書會進行從服務器到客戶端的驗證。當服務器收到預備主秘密時,它使用私鑰進行解密。服務端擁有私鑰是一個證據,可以證明服務器是一個它在第一個信息發送的公鑰證書中要求的實體。
其他的幾種密鑰交換算法這里就不介紹了。可以參考Behrouz A.Forouzan著的《密碼學與網絡安全》。
1.3 客戶機鑒別與密鑰交換:

客戶機啟動SSL握手第3階段,是本階段所有消息的唯一發送方,服務器是所有消息的唯一接收方。該階段分為3步:
(a)證書(可選):為了對服務器證明自身,客戶要發送一個證書信息,這是可選的,在IIS中可以配置強制客戶端證書認證。
(b)客戶機密鑰交換(Pre-master-secret):這里客戶端將預備主密鑰發送給服務端,注意這里會使用服務端的公鑰進行加密。
(c)證書驗證(可選),對預備秘密和隨機數進行簽名,證明擁有(a)證書的公鑰。
下面也重點介紹一下RSA方式的客戶端驗證和密鑰交換。

這種情況,除非服務器在階段II明確請求,否則沒有證書信息。客戶端密鑰交換方法包括階段II收到的由RSA公鑰加密的預備主密鑰。
階段III之后,客戶要有服務器進行驗證,客戶和服務器都知道預備主密鑰。
1.4 完成

客戶機啟動SSL握手第4階段,使服務器結束。該階段分為4步,前2個消息來自客戶機,后2個消息來自服務器。
1.5密鑰生成的過程
這樣握手協議完成,下面看下什么是預備主密鑰,主密鑰是怎么生成的。為了保證信息的完整性和機密性,SSL需要有六個加密秘密:四個密鑰和兩個IV。為了信息的可信性,客戶端需要一個密鑰(HMAC),為了加密要有一個密鑰,為了分組加密要一個IV,服務也是如此。SSL需要的密鑰是單向的,不同於那些在其他方向的密鑰。如果在一個方向上有攻擊,這種攻擊在其他方向是沒影響的。生成過程如下:



2、記錄協議
記錄協議在客戶機和服務器握手成功后使用,即客戶機和服務器鑒別對方和確定安全信息交換使用的算法后,進入SSL記錄協議,記錄協議向SSL連接提供兩個服務:
(1)保密性:使用握手協議定義的秘密密鑰實現
(2)完整性:握手協議定義了MAC,用於保證消息完整性
記錄協議的過程:

SSL記錄的首部:
類型(type):8位,指明上層協議的類型。 改變密碼規約協議的值:20. 告警協議:21 握手協議:22 應用數據協議:23
版本(version):TLS協議版本,長度為16位
長度(length):加密后數據的長度
數據分片的密文數據,附帶MAC摘要。
3、警報協議
客戶機和服務器發現錯誤時,向對方發送一個警報消息。如果是致命錯誤,則算法立即關閉SSL連接,雙方還會先刪除相關的會話號,秘密和密鑰。每個警報消息共2個字節,第1個字節表示錯誤類型,如果是警報,則值為1,如果是致命錯誤,則值為2;第2個字節制定實際錯誤類型。
總結
SSL中,使用握手協議協商加密和MAC算法以及保密密鑰 ,使用握手協議對交換的數據進行加密和簽名,使用警報協議定義數據傳輸過程中,出現問題如何去解決。
二、 SSL/TLS協議
SSL(Secure Sockets Layer,安全套接層),及其繼任者 TLS(Transport Layer Security,傳輸層安全)是為網絡通信提供安全及數據完整性的一種安全協議。TLS與SSL在傳輸層對網絡連接進行加密。
SSL協議位於TCP/IP協議與各種應用層協議之間,為數據通訊提供安全支持。
SSL協議可分為兩層:
SSL記錄協議(SSL Record Protocol):它建立在可靠的傳輸協議(如TCP)之上,為高層協議提供數據封裝、壓縮、加密等基本功能的支持。
SSL握手協議(SSL Handshake Protocol):它建立在SSL記錄協議之上,用於在實際的數據傳輸開始前,通訊雙方進行身份認證、協商加密算法、交換加密密鑰等。SSL握手協議有三個子協議如圖:
握手協議(Handshake protocol):用於會話建立。
改變密碼規約協議(Change cipher spec protocol):用於通知安全參數的建立。
告警協議(Alert protocol):用於向對方發出告警信息。

SSL/TLS協議棧
SSL/TLS協議主要解決的以下3個問題:
1.客戶端對服務器端的認證
2.服務器端對客戶端的認證
3.在客戶端和服務器端建立安全的數據通道
HTTPS = HTTP over TLS.只需配置瀏覽器和服務器相關設置開啟 TLS,即可實現 HTTPS,TLS 高度解耦,可裝可卸,與上層高級應用層協議相互協作又相互獨立。
1.加密
TLS/SSL 的功能實現主要依賴於三類基本算法:散列函數 Hash、對稱加密和非對稱加密,其利用非對稱加密實現身份認證和密鑰協商,對稱加密算法采用協商的密鑰對數據加密,基於散列函數驗證信息的完整性。
TLS 的基本工作方式是,客戶端使用非對稱加密與服務器進行通信,實現身份驗證並協商對稱加密使用的密鑰,然后對稱加密算法采用協商密鑰對信息以及信息摘要進行加密通信,不同的節點之間采用的對稱密鑰不同,從而可以保證信息只能通信雙方獲取。
例如,在 HTTPS 協議中,客戶端發出請求,服務端會將公鑰發給客戶端,客戶端驗證過后生成一個密鑰再用公鑰加密后發送給服務端(非對稱加密),雙方會在 TLS 握手過程中生成一個協商密鑰(對稱密鑰),成功后建立加密連接。通信過程中客戶端將請求數據用協商密鑰加密后發送,服務端也用協商密鑰解密,響應也用相同的協商密鑰。后續的通信使用對稱加密是因為對稱加解密快,而握手過程中非對稱加密可以保證加密的有效性,但是過程復雜,計算量相對來說也大。
2. 記錄層
記錄協議負責在傳輸連接上交換的所有底層消息,並且可以配置加密。每一條 TLS 記錄以一個短標頭開始。標頭包含記錄內容的類型 (或子協議)、協議版本和長度。原始消息經過分段 (或者合並)、壓縮、添加認證碼、加密轉為 TLS 記錄的數據部分。
3.分片 (Fragmentation)
記錄層將信息塊分割成攜帶 2^14 字節 (16KB) 或更小塊的數據的 TLSPlaintext 記錄。
記錄協議傳輸由其他協議層提交給它的不透明數據緩沖區。如果緩沖區超過記錄的長度限制(2^14),記錄協議會將其切分成更小的片段。反過來也是可能的,屬於同一個子協議的小緩沖區也可以組合成一個單獨的記錄。
-
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;
-
復制代碼
4.記錄壓縮和解壓縮 (Record compression and decompression)
壓縮算法將 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;
-
復制代碼
5.空或標准流加密 (Null or standard stream cipher)
流加密(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
6.CBC 塊加密 (分組加密)
塊加密(如 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 復制代碼
7.記錄有效載荷保護 (Record payload protection)
加密和 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 算法。這可以保證主動網絡攻擊者不能操縱任何加密數據。
8.密鑰計算 (Key calculation)
記錄協議需要一種算法,從握手協議提供的安全性參數生成密鑰、IV 和 MAC secret.
主密鑰 (Master secret): 在連接中雙方共享的一個 48 字節的密鑰 客戶隨機數 (client random): 由客戶端提供的 32 字節值 服務器隨機數 (server random): 由服務器提供的 32 字節值
9. 握手層
- 握手協議的職責是生成通信過程所需的共享密鑰和進行身份認證。這部分使用無密碼套件,為防止數據被竊聽,通過公鑰密碼或 Diffie-Hellman 密鑰交換技術通信。
- 密碼規格變更協議,用於密碼切換的同步,是在握手協議之后的協議。握手協議過程中使用的協議是“不加密”這一密碼套件,握手協議完成后則使用協商好的密碼套件。
- 警告協議,當發生錯誤時使用該協議通知通信對方,如握手過程中發生異常、消息認證碼錯誤、數據無法解壓縮等。
- 應用數據協議,通信雙方真正進行應用數據傳輸的協議,傳送過程通過 TLS 應用數據協議和 TLS 記錄協議來進行傳輸。
握手是 TLS 協議中最精密復雜的部分。在這個過程中,通信雙方協商連接參數,並且完成身 份驗證。根據使用的功能的不同,整個過程通常需要交換 6~10 條消息。根據配置和支持的協議擴展的不同,交換過程可能有許多變種。在使用中經常可以觀察到以下三種流程:(1) 完整的握手, 對服務器進行身份驗證;(2) 恢復之前的會話采用的簡短握手;(3) 對客戶端和服務器都進行身份驗證的握手。
握手協議消息的標頭信息包含消息類型(1 字節)和長度(3 字節),余下的信息則取決於消息類型:
-
struct {
-
HandshakeType msg_type;
-
uint24 length;
-
HandshakeMessage message;
-
} Handshake;
-
復制代碼
9.1 完整握手
每一個 TLS 連接都會以握手開始。如果客戶端此前並未與服務器建立會話,那么雙方會執行一次完整的握手流程來協商 TLS 會話。握手過程中,客戶端和服務器將進行以下四個主要步驟:
- 交換各自支持的功能,對需要的連接參數達成一致
- 驗證出示的證書,或使用其他方式進行身份驗證
- 對將用於保護會話的共享主密鑰達成一致
- 驗證握手消息並未被第三方團體修改
下面介紹最常見的握手規則,一種不需要驗證客戶端身份但需要驗證服務器身份的握手:
9.1.1 ClientHello
這條消息將客戶端的功能和首選項傳送給服務器。
Version: 協議版本(protocol version)指示客戶端支持的最佳協議版本
- Random: 一個 32 字節數據,28 字節是隨機生成的 (圖中的 Random Bytes);剩余的 4 字節包含額外的信息,與客戶端時鍾有關 (圖中使用的是 GMT Unix Time)。在握手時,客戶端和服務器都會提供隨機數,客戶端的暫記作 random_C (用於后續的密鑰的生成)。這種隨機性對每次握手都是獨一無二的,在身份驗證中起着舉足輕重的作用。它可以防止 重放攻擊,並確認初始數據交換的完整性。
- Session ID: 在第一次連接時,會話 ID(session ID)字段是空的,這表示客戶端並不希望恢復某個已存在的會話。典型的會話 ID 包含 32 字節隨機生成的數據,一般由服務端生成通過 ServerHello 返回給客戶端。
- Cipher Suites: 密碼套件(cipher suite)塊是由客戶端支持的所有密碼套件組成的列表,該列表是按優先級順序排列的
- Compression: 客戶端可以提交一個或多個支持壓縮的方法。默認的壓縮方法是 null,代表沒有壓縮
- Extensions: 擴展(extension)塊由任意數量的擴展組成。這些擴展會攜帶額外數據
9.1.2 ServerHello
是將服務器選擇的連接參數傳回客戶端。
這個消息的結構與 ClientHello 類似,只是每個字段只包含一個選項,其中包含服務端的 random_S 參數 (用於后續的密鑰協商)。服務器無需支持客戶端支持的最佳版本。如果服務器不支持與客戶端相同的版本,可以提供某個其他版本以期待客戶端能夠接受
圖中的 Cipher Suite 是后續密鑰協商和身份驗證要用的加密套件,此處選擇的密鑰交換與簽名算法是 ECDHE_RSA,對稱加密算法是 AES-GCM,后面會講到這個
還有一點默認情況下 TLS 壓縮都是關閉的,因為 CRIME 攻擊會利用 TLS 壓縮恢復加密認證 cookie,實現會話劫持,而且一般配置 gzip 等內容壓縮后再壓縮 TLS 分片效益不大又額外占用資源,所以一般都關閉 TLS 壓縮
9.1.3 Certificate
典型的 Certificate 消息用於攜帶服務器 X.509 證書鏈。 服務器必須保證它發送的證書與選擇的算法套件一致。比方說,公鑰算法與套件中使用的必須匹配。除此以外,一些密鑰交換算法依賴嵌入證書的特定數據,而且要求證書必須以客戶端支持的算法簽名。所有這些都表明服務器需要配置多個證書(每個證書可能會配備不同的證書鏈)。
Certificate 消息是可選的,因為並非所有套件都使用身份驗證,也並非所有身份驗證方法都需要證書。更進一步說,雖然消息默認使用 X.509 證書,但是也可以攜帶其他形式的標志;一些套件就依賴 PGP 密鑰
9.1.4 ServerKeyExchange
攜帶密鑰交換需要的額外數據。ServerKeyExchange 是可選的,消息內容對於不同的協商算法套件會存在差異。部分場景下,比如使用 RSA 算法時,服務器不需要發送此消息。
ServerKeyExchange 僅在服務器證書消息(也就是上述 Certificate 消息)不包含足夠的數據以允許客戶端交換預主密鑰(premaster secret)時才由服務器發送。
比如基於 DH 算法的握手過程中,需要單獨發送一條 ServerKeyExchange 消息帶上 DH 參數:
9.1.5 ServerHelloDone
表明服務器已經將所有預計的握手消息發送完畢。在此之后,服務器會等待客戶端發送消息。
9.1.6 verify certificate
客戶端驗證證書的合法性,如果驗證通過才會進行后續通信,否則根據錯誤情況不同做出提示和操作,合法性驗證內容包括如下:
- 證書鏈的可信性 trusted certificate path;
- 證書是否吊銷 revocation,有兩類方式 - 離線 CRL 與在線 OCSP,不同的客戶端行為會不同;
- 有效期 expiry date,證書是否在有效時間范圍;
- 域名 domain,核查證書域名是否與當前的訪問域名匹配;
由 PKI 體系 的內容可知,對端發來的證書簽名是 CA 私鑰加密的,接收到證書后,先讀取證書中的相關的明文信息,采用相同的散列函數計算得到信息摘要,然后利用對應 CA 的公鑰解密簽名數據,對比證書的信息摘要,如果一致,則可以確認證書的合法性;然后去查詢證書的吊銷情況等
9.1.7 ClientKeyExchange
合法性驗證通過之后,客戶端計算產生隨機數字的預主密鑰(Pre-master),並用證書公鑰加密,發送給服務器並攜帶客戶端為密鑰交換提供的所有信息。這個消息受協商的密碼套件的影響,內容隨着不同的協商密碼套件而不同。
此時客戶端已經獲取全部的計算協商密鑰需要的信息: 兩個明文隨機數 random_C 和 random_S 與自己計算產生的 Pre-master,然后得到協商密鑰(用於之后的消息加密)
-
enc_key = PRF(Pre_master, "master secret", random_C + random_S)
-
復制代碼
圖中使用的是 ECDHE 算法,ClientKeyExchange 傳遞的是 DH 算法的客戶端參數,如果使用的是 RSA 算法則此處應該傳遞加密的預主密鑰
9.1.8 ChangeCipherSpec
通知服務器后續的通信都采用協商的通信密鑰和加密算法進行加密通信
注意 ChangeCipherSpec 不屬於握手消息,它是另一種協議,只有一條消息,作為它的子協議進行實現。
9.1.9 Finished (Encrypted Handshake Message)
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 字節的定長消息。
9.1.10 Server
服務器用私鑰解密加密的 Pre-master 數據,基於之前交換的兩個明文隨機數 random_C 和 random_S,同樣計算得到協商密鑰: enc_key = PRF(Pre_master, "master secret", random_C + random_S);
同樣計算之前所有收發信息的 hash 值,然后用協商密鑰解密客戶端發送的 verify_data_C,驗證消息正確性;
9.1.11 change_cipher_spec
服務端驗證通過之后,服務器同樣發送 change_cipher_spec 以告知客戶端后續的通信都采用協商的密鑰與算法進行加密通信(圖中多了一步 New Session Ticket,此為會話票證,會在會話恢復中解釋);
9.1.12 Finished (Encrypted Handshake Message)
服務器也結合所有當前的通信參數信息生成一段數據 (verify_data_S) 並采用協商密鑰 session secret (enc_key) 與算法加密並發送到客戶端;
9.1.13 握手結束
客戶端計算所有接收信息的 hash 值,並采用協商密鑰解密 verify_data_S,驗證服務器發送的數據和密鑰,驗證通過則握手完成;
9.1.14 加密通信
開始使用協商密鑰與算法進行加密通信。
9.2 密鑰交換和簽名算法
常用的密鑰交換和簽名算法
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 密鑰交換和 DH 密鑰交換的區別
使用 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 一般取個較小值就可以
可以看到雙方發給對方的參數中攜帶了一個公鑰值,對應上述的 A 和 B
而且實際用的加密套件是 橢圓曲線 DH 密鑰交換 (ECDH),利用由橢圓曲線加密建立公鑰與私鑰對可以更進一步加強 DH 的安全性,因為目前解決橢圓曲線離散對數問題要比因式分解困難的多,而且 ECC 使用的密鑰長度比 RSA 密鑰短得多(目前 RSA 密鑰需要 2048 位以上才能保證安全,而 ECC 密鑰 256 位就足夠)
關於 橢圓曲線密碼學 - ECC,推薦看下 A Primer on Elliptic Curve Cryptography - 原文 - 譯文
9.3 客戶端身份驗證
盡管可以選擇對任意一端進行身份驗證,但人們幾乎都啟用了對服務器的身份驗證。如果服務器選擇的套件不是匿名的,那么就需要在 Certificate 消息中跟上自己的證書。
相比之下,服務器通過發送 CertificateRequest 消息請求對客戶端進行身份驗證。消息中列出所有可接受的客戶端證書。作為響應,客戶端發送自己的 Certificate 消息(使用與服務器發送證書相同的格式),並附上證書。此后,客戶端發送 CertificateVerify 消息,證明自己擁有對應的私鑰。
只有已經過身份驗證的服務器才被允許請求客戶端身份驗證。基於這個原因,這個選項也被稱為相互身份驗證(mutual authentication)。
9.3.1 CertificateRequest
在 ServerHello 的過程中發出,請求對客戶端進行身份驗證,並將其接受的證書的公鑰和簽名算法傳送給客戶端。
它也可以選擇發送一份自己接受的證書頒發機構列表,這些機構都用其可分辨名稱來表示:
-
struct {
-
ClientCertificateType certificate_types;
-
SignatureAndHashAlgorithm supported_signature_algorithms;
-
DistinguishedName certificate_authorities;
-
} CertificateRequest;
-
復制代碼
9.3.2 CertificateVerify
在 ClientKeyExchange 的過程中發出,證明自己擁有的私鑰與之前發送的客戶端證書中的公鑰匹配。消息中包含一條到這一步為止的所有握手消息的簽名:
-
struct {
-
Signature handshake_messages_signature;
-
} CertificateVerify;
-
復制代碼
9.4 會話恢復
最初的會話恢復機制是,在一次完整協商的連接斷開時,客戶端和服務器都會將會話的安全參數保存一段時間。希望使用會話恢復的服務器為會話指定唯一的標識,稱為會話 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 安全模型。它使用票證密鑰加密的會話狀態並將其暴露在線路上。有些實現中的票證密鑰可能會比連接使用的密碼要弱。如果票證密鑰被暴露,就可以解密連接上的全部數據。因此,使用會話票證時,票證密鑰需要頻繁輪換。
References
- RFC 2246 - The TLS Protocol Version 1.0
- NPN/ALPN - wiki
- TLS - wiki
- SSL/TLS in detail
- HTTPS 加密協議詳解
- Keyless SSL: The Nitty Gritty Technical Details
- DSA - 數字簽名算法
- 《HTTPS 權威指南 - 在服務器和 web 應用上部署 SSL/TLS 和 PKI》
轉載於:https://juejin.im/post/5b88a93df265da43231f1451
三、利用wireshark進行SSL/TLS協議的驗證---以登陸163郵箱為例子
確保瀏覽器開啟了SSL、TLS功能

TLS數據包列表

客戶端 Client Hello 報文

server hello報文

服務器認證報文
————————————————
版權聲明:本文為CSDN博主「Chaos_Ju」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/chaosju/article/details/39897799
