傳輸安全HTTPS

2023-03-13 15:04:48

為什麼要有 HTTPS

為什麼要有 HTTPS?簡單的回答是:「因為 HTTP 不安全」。HTTP 怎麼不安全呢?

  • 通訊的訊息會被竊取,無法保證機密性(保密性):由於 HTTP 是 「明文」 傳輸,整個通訊過程完全透明,其他人能夠竊取到傳輸的明文資訊。
  • 通訊的訊息會被篡改,無法保證完整性:使用 HTTP 通訊,任何人都能夠在通訊的過程中截獲並篡改請求報文、響應報文,但訊息接收者無法識別報文是否被篡改。
  • 通訊的訊息會被偽造,無法確認訊息傳送者的真實身份(身份認證):使用 HTTP 通訊,任何人都能夠給一個接收者傳送訊息,但是訊息接收者無法確認訊息傳送者的真實身份。也就是說,無法進行身份認證。
  • 無法保證不可否認性(不可抵賴):使用 HTTP 通訊,訊息接收者收到一個訊息後,通訊的一方可以否認(抵賴)訊息不是他傳送的。也就是說,訊息接收者無法證明這一訊息的確是由通訊的一方傳送的。

只有同時具備了機密性、完整性、身份認證、不可否認這四個特性,才能算得上是安全的通訊。

HTTPS 使用 HTTP 進行通訊,並使用 SSL/TLS 為 HTTP 增加了機密性、完整性、身份認證、不可否認這四大安全特性。

介紹 SSL/TLS

SSL 即安全通訊協定(Secure Sockets Layer)。

SSL 發展到 v3 時已經證明了它是一個非常好的安全通訊協定,於是網際網路工程組 IETF 在 1999 年把 SSL 改名為 TLS(傳輸層安全,Transport Layer Security),正式標準化,版本號從 1.0 重新算起,所以 TLS1.0 實際上就是 SSLv3.1。

至今,TLS 已經發展出了三個版本,分別是 2006 年的 1.1、2008 年的 1.2 和 2018 的 1.3,每個新版本都緊跟密碼學的發展和網際網路的現狀,持續強化安全和效能。目前應用最廣泛的 TLS 版本是 1.2,而之前的版本(TLS1.1 / 1.0、SSLv3 / v2)都已經被認為是不安全的。

TLS 綜合使用了對稱加密、非對稱加密、身份認證等許多密碼學前沿技術。非對稱加密在這個場景中發揮的作用是 「金鑰協商」,通訊的雙方協商得到對談金鑰。對談金鑰用於 HTTP 報文的加解密,以實現機密性。


TLS 由記錄協定、握手協定、警報協定、變更密碼規範協定、擴充套件協定等幾個子協定組成:

  • 記錄協定(Record Protocol)規定了 TLS 收發資料的基本單位是:記錄(record)。它有點像是 TCP 裡的 segment,所有其他的子協定都需要通過記錄協定發出。多個記錄資料可以在一個 TCP 包裡一次性發出。
  • 握手協定(Handshake Protocol)是 TLS 裡最複雜的子協定。通訊的雙方在 TLS 握手的過程中協商 TLS 的版本號、密碼套件,交換亂數、數位憑證和金鑰引數,最終通訊的雙方協商得到對談金鑰。
  • 警報協定(Alert Protocol)的職責是向對方發出警報資訊。收到警報的一方可以選擇繼續連線,也可以立即終止連線。它有點像是 HTTP 裡的狀態碼,比如 protocol_version 就是不支援舊版本,bad_certificate 就是證書有問題。
  • 變更密碼規範協定(Change Cipher Spec Protocol)就是一個「通知」,告訴對方:後續傳輸的都是對稱金鑰加密的密文。也就是說,「Change Cipher Spec」 訊息之前傳輸的都是明文,之後傳輸的都是對稱金鑰加密的密文。

TLS 的金鑰套件

通訊的雙方在 TLS 握手的過程中會協商使用的密碼套件(cipher suite,也被稱為加密套件)。

TLS 的密碼套件命名非常規範。固定的格式是:「金鑰交換演演算法 + 簽名演演算法 + 對稱加密演演算法 + 分組模式 + 訊息摘要演演算法」,例如 「ECDHE-RSA-AES256-GCM-SHA384」 密碼套件的意思就是:

  • 金鑰交換演演算法使用的是:ECDHE。通訊的雙方在 TLS 握手的過程中協商 TLS 的版本號、密碼套件,交換亂數、數位憑證和金鑰引數,通訊的雙方使用 ECDHE 演演算法演演算法 "Pre Master Secret"。

  • 簽名演演算法使用的是:RSA。TLS 握手的過程中,使用 RSA 簽名演演算法進行數位簽章。伺服器給瀏覽器傳送 "Server Key Exchange" 訊息,伺服器對金鑰引數(訊息中的 Public 引數)進行數位簽章,然後把簽名值一併行送給瀏覽器。瀏覽器收到 "Server Key Exchange" 訊息後,使用數位憑證中的公鑰對金鑰引數(訊息中的 Public 引數)進行驗籤。

  • 對稱加密演演算法使用的是:AES-256。TLS 握手後的通訊使用 AES 對稱加密演演算法進行加密,以實現機密性。對稱金鑰的長度 256 位

  • 分組模式使用的是:GCM。加密明文的長度不固定,而一次對稱加密只能處理特定長度的一塊資料,這就需要進行迭代,以便將一段很長的資料全部加密,而迭代的方法就是分組模式。

  • 訊息摘要演演算法使用的是:SHA-384。TLS 握手的過程中,兩次用到了該訊息摘要演演算法。一次是:「PRF」 通過訊息摘要演演算法,根據三個亂數(Client Random、Server Random 和 Pre Master Secret)計算主金鑰 "Master Secret" 的值。另一次是:通訊的雙方給對方傳送 "Finished" 訊息。一方對之前傳送的資料做摘要,再使用對談金鑰對摘要進行對稱加密,讓對方進行驗證(類似數位簽章的驗籤)。TLS 握手後的通訊使用該訊息摘要演演算法進行訊息認證,防止訊息被篡改。

TLS1.2 握手的過程

使用 HTTPS 協定通訊,通訊的雙方會先建立 TCP 連線,然後執行 TLS 握手,之後就可以在安全的通訊環境裡收發 HTTP 請求和響應了。

執行 TLS 握手的目的是:通訊的雙方安全的協商對談金鑰。對談金鑰用於 HTTP 報文的加解密,以實現機密性。


TLS1.2 握手可以劃分為兩種方式:使用 RSA 演演算法實現金鑰交換 和 使用 ECDHE 演演算法實現金鑰交換。

下面說的是使用 ECDHE 演演算法實現金鑰交換的 TLS 握手過程。

TLS 握手過程的簡要描述:通訊的雙方在 TLS 握手的過程中協商 TLS 的版本號、密碼套件,交換亂數、數位憑證和金鑰引數,最終通訊的雙方協商得到對談金鑰。"Hello" 訊息交換亂數,"Key Exchange" 訊息交換金鑰引數。

  • 瀏覽器給伺服器傳送 "Client Hello" 訊息,伺服器給瀏覽器傳送 "Server Hello" 訊息。通訊的雙方協商 TLS 的版本號、密碼套件,並交換亂數。
  • 交換數位憑證:伺服器為了向瀏覽器證明自己的身份,伺服器給瀏覽器傳送 "server Certificate" 訊息,以傳送數位憑證鏈,其中包含了兩個證書。一個是 CA 機構頒發的數位憑證,另一個是 CA 機構的數位憑證。
  • 伺服器給瀏覽器傳送 "Server Key Exchange" 訊息,瀏覽器給伺服器傳送 "Client Key Exchange" 訊息。通訊的雙方交換金鑰引數(Client Params 和 Server Params),然後通訊的雙方使用 ECDHE 演演算法算出 "Pre Master Secret"。
  • 通訊的雙方根據自己已知的引數(Client Random、Server Random 和 Pre Master Secret)算出主金鑰 "Master Secret",並使用主金鑰拓展出更多的金鑰(對談金鑰),避免只用一個金鑰帶來的安全隱患。
  • 瀏覽器給伺服器傳送 "Change Cipher Spec" 訊息,伺服器也給瀏覽器傳送 "Change Cipher Spec" 訊息。告訴對方:後續傳輸的都是對稱金鑰加密的密文。
  • 瀏覽器給伺服器傳送 "Finished" 訊息,伺服器也給瀏覽器傳送 "Finished" 訊息。通訊的雙方把之前傳送的資料做摘要,再使用對談金鑰對摘要進行對稱加密,讓對方進行驗證(類似數位簽章的驗籤)。
  • 雙方都驗證成功,握手正式結束,之後就可以正常收發被加密的 HTTP 請求和響應了。

TLS 握手的過程如下圖所示,其中每一個框都是一個記錄,多個記錄組合成一個 TCP 包傳送。所以,最多經過兩次訊息往返(4 個訊息,或者說 4 個 TCP 包)就可以完成 TLS 握手。

第一個訊息往返

瀏覽器與伺服器建立 TCP 連線之後,瀏覽器會首先給伺服器傳送 "Client Hello" 訊息。"Client Hello" 訊息攜帶幾個引數:Version、Random、Cipher Suites。

  • Version:TLS 的版本號
  • Random:瀏覽器生成的亂數(Client Random)。亂數用於後續生成主金鑰
  • Cipher Suites:瀏覽器支援的密碼套件
Handshake Protocol: Client Hello
    Version: TLS 1.2 (0x0303)
    Random: 1cbf803321fd2623408dfe…
    Cipher Suites (17 suites)
        Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
        Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)

伺服器收到瀏覽器傳送的 "Client Hello" 訊息後,伺服器給瀏覽器傳送 "Server Hello" 訊息。"Server Hello" 訊息攜帶幾個引數:Version、Random、Cipher Suite。

  • Version:TLS 的版本號
  • Random:伺服器生成的亂數(Server Random)。亂數用於後續生成主金鑰
  • Cipher Suite:伺服器選擇使用的密碼套件(伺服器從瀏覽器傳送的 "Client Hello" 訊息的 Cipher Suites 引數中選)
Handshake Protocol: Server Hello
    Version: TLS 1.2 (0x0303)
    Random: 0e6320f21bae50842e96…
    Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)

伺服器為了向瀏覽器證明自己的身份,伺服器給瀏覽器傳送一個證書鏈,包含了兩個證書。一個是 CA 機構頒發的數位憑證,另一個是 CA 機構的數位憑證。

通過引入數位憑證,實現了伺服器的身份認證功能,這樣即便駭客偽造了伺服器,但是由於數位憑證是沒有辦法偽造的,所以駭客依然無法欺騙使用者。


由於伺服器選擇了使用 ECDHE 金鑰交換演演算法,因此伺服器需要給瀏覽器傳送【伺服器端的橢圓曲線的公鑰】(Server Params)。為了防止公鑰被第三方篡改、被駭客冒充,伺服器會對公鑰進行數位簽章,然後把簽名值一併行送給瀏覽器。瀏覽器收到後,使用數位憑證中的公鑰對金鑰引數(訊息中的 Public 引數)進行驗籤。

伺服器給瀏覽器傳送 "Server Key Exchange" 訊息。"Server Key Exchange" 訊息攜帶幾個引數:Curve Type、Named Curve、Pubkey、Signature Algorithm、Signature。

  • Curve Type、Named Curve:使用的橢圓曲線的型別
  • Pubkey:根據【伺服器端的橢圓曲線的私鑰】和 基點 G 計算出的【伺服器端的橢圓曲線的公鑰】(Server Params),用於後續計算 「Pre Master Secret」
  • Signature Algorithm、Signature:使用的簽名演演算法、簽名值
Handshake Protocol: Server Key Exchange
    EC Diffie-Hellman Server Params
        Curve Type: named_curve (0x03)
        Named Curve: x25519 (0x001d)
        Pubkey: 3b39deaf00217894e...
        Signature Algorithm: rsa_pkcs1_sha512 (0x0601)
        Signature: 37141adac38ea4...

伺服器給瀏覽器傳送 "Server Key Exchange" 訊息之後,伺服器傳送資訊完畢。伺服器給瀏覽器傳送 "Server Hello Done" 訊息,伺服器向瀏覽器說明:伺服器傳送資訊完畢了。

至此,第一個訊息往返就結束了(2 個訊息,或者說 2 個 TCP 包)。結果是:通訊的雙方通過明文傳輸共用瞭如下資訊:瀏覽器生成的亂數(Client Random)、伺服器生成的亂數(Server Random)、使用的橢圓曲線的型別、伺服器端的橢圓曲線的公鑰(Server Params)。

驗證數位憑證

瀏覽器收到伺服器傳送的數位憑證之後,瀏覽器需要驗證數位憑證是否合法、有效。

瀏覽器驗證完數位憑證合法、有效後,瀏覽器再用數位憑證中的公鑰驗證【伺服器給瀏覽器傳送的 "Server Key Exchange" 訊息】的簽名,以確認伺服器的身份。

瀏覽器確認了伺服器的身份之後,就開始了第二個訊息往返。

第二個訊息往返

由於通訊的雙方協商的使用 ECDHE 金鑰交換演演算法。因此瀏覽器需要給伺服器傳送【使用者端的橢圓曲線的公鑰】(Client Params)。瀏覽器給伺服器傳送 "Client Key Exchange" 訊息。

Handshake Protocol: Client Key Exchange
    EC Diffie-Hellman Client Params
        Pubkey: 8c674d0e08dc27b5eaa…

至此,通訊的雙方都獲取到了 ECDHE 金鑰交換演演算法需要的兩個引數(Client Params、Server Params),於是通訊的雙方就使用 ECDHE 演演算法算出一個亂數,這個亂數被叫做 "Pre Master Secret"。

ECDHE 演演算法可以保證:即使駭客截獲了之前的引數,駭客也絕對算不出這個 「Pre Master Secret」 亂數,因為 "Pre Master Secret" 的計算還使用了橢圓曲線的私鑰。

目前,通訊的雙方已知三個亂數:Client Random、Server Random 和 Pre Master Secret。通訊的雙方使用這三個亂數作為原始資訊,通過 PRF 算出主金鑰(Master Secret)。因為駭客拿不到 "Pre Master Secret",所以駭客也就無法得到主金鑰。

主金鑰 "Master Secret" 的計算:這裡的 「PRF」 就是偽亂數函數,它基於密碼套件裡的最後一個引數(訊息摘要演演算法),比如 SHA384。「PRF」 通過 SHA384 訊息摘要演演算法再一次強化 "Master Secret" 的隨機性。

master_secret = PRF(pre_master_secret, "master secret", ClientHello.random + ServerHello.random)

主金鑰的長度為 48 位元組,但是主金鑰並不是最終用於通訊的對談金鑰,還會再用 PRF 擴充套件出更多的金鑰,比如瀏覽器傳送用的對談金鑰(client_write_key)、伺服器傳送用的對談金鑰(server_write_key)等,避免只用一個金鑰帶來的安全隱患。有了主金鑰和派生的對談金鑰,TLS 握手就快結束了。


瀏覽器給伺服器傳送 "Change Cipher Spec" 訊息。瀏覽器告訴伺服器:瀏覽器後續傳輸的都是對稱金鑰加密的密文。瀏覽器給伺服器傳送 "Finished" 訊息。瀏覽器對之前傳送的資料做摘要,再使用對談金鑰對摘要進行對稱加密,讓伺服器進行驗證(類似數位簽章的驗籤)。

伺服器也進行和瀏覽器同樣的操作。

  • 伺服器給瀏覽器傳送 "Change Cipher Spec" 訊息。伺服器告訴瀏覽器:伺服器後續傳輸的都是對稱金鑰加密的密文。
  • 伺服器給瀏覽器傳送 "Finished" 訊息。瀏覽器對之前傳送的資料做摘要,再使用對談金鑰對摘要進行對稱加密,讓瀏覽器進行驗證。

雙方都驗證成功,握手正式結束,之後就可以正常收發被加密的 HTTP 請求和響應了。

使用 RSA 的 TLS 握手

TLS1.2 握手可以劃分為兩種方式:使用 RSA 演演算法實現鑰交換 和 使用 ECDHE 演演算法實現金鑰交換。

上面說了【使用 ECDHE 演演算法實現金鑰交換的 TLS 握手過程】,下面說【使用 RSA 演演算法實現金鑰交換的 TLS 握手過程】。

TLS 握手過程的簡要描述:通訊的雙方在 TLS 握手的過程中協商 TLS 的版本號、密碼套件,交換亂數、數位憑證和金鑰引數,最終通訊的雙方協商得到對談金鑰。"Hello" 訊息交換亂數,"Key Exchange" 訊息交換 "Pre Master Secret"。

  • 瀏覽器給伺服器傳送 "Client Hello" 訊息,伺服器給瀏覽器傳送 "Server Hello" 訊息。通訊的雙方協商 TLS 的版本號、密碼套件,並交換亂數。
  • 交換數位憑證:伺服器為了向瀏覽器證明自己的身份,伺服器給瀏覽器傳送 "server Certificate" 訊息,以傳送數位憑證鏈,其中包含了兩個證書。一個是 CA 機構頒發的數位憑證,另一個是 CA 機構的數位憑證。
  • 伺服器給瀏覽器傳送 "Server Hello Done" 訊息,伺服器向瀏覽器說明:伺服器傳送資訊完畢了。
  • 瀏覽器驗證數位憑證合法、有效後,獲取數位憑證中【伺服器的公鑰】。瀏覽器生成亂數 "Pre Master Secret",使用【伺服器的公鑰】對生成的 "Pre Master Secret" 進行加密。然後,瀏覽器給伺服器傳送 "Client Key Exchange" 訊息,把加密後的 "Pre Master Secret" 傳送給伺服器。
  • 伺服器收到瀏覽器傳送的 "Client Key Exchange" 訊息後,使用【伺服器的私鑰】解密出亂數 "Pre Master Secret"。
  • 通訊的雙方根據自己已知的引數(Client Random、Server Random 和 Pre Master Secret)算出主金鑰 "Master Secret",並使用主金鑰拓展出更多的金鑰(對談金鑰),避免只用一個金鑰帶來的安全隱患。
  • 瀏覽器給伺服器傳送 "Change Cipher Spec" 訊息,伺服器也給瀏覽器傳送 "Change Cipher Spec" 訊息。告訴對方:後續傳輸的都是對稱金鑰加密的密文。
  • 瀏覽器給伺服器傳送 "Finished" 訊息,伺服器也給瀏覽器傳送 "Finished" 訊息。通訊的雙方把之前傳送的資料做摘要,再使用對談金鑰對摘要進行對稱加密,讓對方進行驗證(類似數位簽章的驗籤)。
  • 雙方都驗證成功,握手正式結束,之後就可以正常收發被加密的 HTTP 請求和響應了。

【使用 RSA 演演算法實現鑰交換的 TLS 握手過程】的大體流程沒有變,只是 "Pre Master Secret" 不再需要通訊的雙方根據金鑰引數使用演演算法算出,而是由瀏覽器生成,瀏覽器再使用伺服器的公鑰對生成的 "Pre Master Secret" 進行加密。然後,瀏覽器給伺服器傳送 "Server Key Exchange" 訊息,把加密後的 "Pre Master Secret" 傳送給伺服器。伺服器收到瀏覽器傳送的 "Server Key Exchange" 訊息後,使用伺服器的私鑰解密出亂數 "Pre Master Secret"。

這樣通訊的雙方也已知三個亂數:Client Random、Server Random 和 Pre Master Secret,就可以生成主金鑰了。

參考資料

23 | HTTPS是什麼?SSL/TLS又是什麼? (geekbang.org)

26 | 信任始於握手:TLS1.2連線過程解析 (geekbang.org)

3.4 HTTPS ECDHE 握手解析 | 小林coding (xiaolincoding.com)