SSL/TLS 協議位于網絡 OSI 七層模型的會話層,用來加密通信。SSL(Secure Sockets Layer,安全套接字層)是一種標準安全協議,用于在在線通信中建立Web服務器和瀏覽器之間的加密鏈接。SSL 通過互相認證、使用數字簽名確保完整性、使用加密確保私密性,以實現客戶端和服務器之間的安全通訊。
TLS(Transport Layer Security,傳輸層安全)是 IETF 在 SSL 3.0 的基礎上設計的協議,它是 SSL 協議的升級版。兩者差別極小,可以理解為 TLS 是 SSL 3.1。
TLS 協議結構
TLS 協議分成兩層:TLS 記錄協議(TLS record protocol)、TLS 握手協議(TLS handshake protocol)

TLS 握手協議負責加密以外的其他事情。握手協議分成 4 個子協議,分別是:
- 握手協議 :負責通信雙方之間協商決定密碼算法和共享密鑰
- 密碼規格變更協議 :負責向通信對象傳達變更密碼方式的信號
- 警告協議 :負責在發生錯誤時將錯誤傳給對方
- 應用數據協議 :是將TLS承載的應用數據傳達給通訊對象
TLS 記錄協議負責消息的壓縮、加密以及數據的認證。TLS 記錄協議使用到的所有的算法等都是經過握手協議協商確認后的,以保證通訊雙方是使用相同的算法。處理過程:
- 首先,消息會被分割成多份,并用協商好的壓縮算法進行壓縮。
- 其次,壓縮片段會加上消息認證碼以保證完整性,為了防止重放攻擊還加上了片段編號。
- 再次,壓縮后的消息片段會加上消息認證碼一起進行加密。加密使用 CBC 模式,初始向量是通過主密碼生成。
- 最后,加密后的報文,再加上數據類型、版本號、壓縮后的長度組成的報頭,就是最終的數據報文。
握手過程

- ClientHello(客戶端 -> 服務器)
- 客戶端向服務端發送自己的信息:可用的版本號、當前時間、客戶端隨機數、會話ID、可用的密碼套件清單、可用的壓縮方式清單。
- 可用的版本號、可用的密碼套件清單、可用的壓縮方式清單:因為不同的瀏覽器可能支持的情況不一樣,所以需要發送給服務端以方便協商。
- 當前時間:TLS不使用,但是上層的協議有可能使用。
- 客戶端隨機數:后面會使用到。
- 會話ID:客戶端和服務端需要重新使用之前的連接時,會使用到此信息。
- ServerHello(服務器 -> 客戶端)
- 服務端向客戶端發送自己的信息:使用的版本號、當前時間、服務器隨機數、會話ID、使用的密碼套件清單、使用的壓縮方式清單
- 使用的版本號、使用的密碼套件清單、使用的壓縮方式清單:這里發送的就是協商后的確定結果
- 當前時間:TLS不使用,但是上層的協議有可能使用
- 服務器隨機數:后面會使用到
- Certificate(服務器 -> 客戶端)
- 發送服務器的證書,包含證書清單,客戶端會對其進行驗證。如果是匿名通信,則不發送該消息。
- 如果 Certificate 不足以滿足需求時,則會發送 ServerKeyExchange (服務器 -> 客戶端)消息。具體的內容根據密碼套件的不同而有所不同。這個不是必須的。
- 雙向認證,服務器則會發送 CertificateRquest(服務器 -> 客戶端)找客戶端要其證書用來驗證。這個也不是必須的。
- ServerHelloDone(服務器 -> 客戶端)
- 通知客戶端 Hello 時間結束。
- 如果服務器要了客戶端的證書,則客戶端發送 Certificate(客戶端 -> 服務器)將其證書發送給服務器。
- ClientKeyExchange(客戶端 -> 服務器)
- 這個就是最關鍵的一步,交換生成最終密鑰的關鍵素材。
- 如果是使用的 RSA,則會將經過服務器公鑰加密的預備主密碼隨著 ClientKeyExchange 消息一起發送。
- 如果是 Diffie-Hellman 密鑰交換,則隨著 ClientKeyExchange 消息一起發送的是 Diffie-Hellman 公開值。
- 預備主密碼使得服務端和客戶端分別計算出相同的主密碼。
- 如果服務器向客戶端發送了消息,客戶端還會向服務器發送 CertificateVerify(客戶端 -> 服務器)消息,這是為了向服務器證明,自己確實是真實的客戶端,擁有客戶端證書的私鑰。為了實現這個目的,客戶端會計算主密碼和握手協議種傳送的消息的散列值加上自己的數字簽名后發送給服務器。
- 生成密鑰
- 根據關鍵的密鑰素材主密碼生成:對稱密碼的密鑰、消息認證碼的密鑰、對稱密碼的CBC模式中使用的初始化向量
- ChangeCipherSpec(客戶端 -> 服務器)和 Finished(客戶端 -> 服務器)
- ChangeCipherSpec這不是握手協議,而是密碼規格變更協議。客戶端告訴服務器我要換密碼了。因為已經雙方已經交換了密碼套件信息,可以開始切換密碼進行通信了。
- Finished代表客戶端已經搞定了
- ChangeCipherSpec(服務器 -> 客戶端) 和 Finished(服務器 -> 客戶端)
- ChangeCipherSpec服務器告訴客戶端,我要開始換密碼了
- Finished代表服務器已經搞定了