HTTPS 與 TLS 的真實運作方式:握手過程詳解

Security2026-10-21TryQuickToolBox

你加裝了憑證,瀏覽器顯示鎖頭圖示,然後就繼續往下走了。直到某天,一個 API 客戶端因 SSL_ERROR_RX_RECORD_TOO_LONG 而失敗,行動應用程式拒絕你的憑證鏈,或是啟用 HSTS 後出現重新導向迴圈。突然間,HTTPS 變成了一個黑箱。

本文要打開這個黑箱。我們將逐步說明 TLS 握手中實際發生的事、憑證存在的理由、對稱與非對稱加密各自扮演的角色,以及如何在生產環境中除錯你確實會遇到的失敗情況。

HTTPS 究竟是什麼

HTTPS 並不是一個獨立的協定。它就是在 TLS 加密連線上傳送的普通 HTTP。URL 的 scheme 改變了,預設連接埠從 80 變成 443,其他一切——方法、標頭、狀態碼、Cookie——行為都相同。

TLS 在 TCP 之上提供三項保證:

第三項保證是最常被低估的。沒有認證的加密毫無價值:能攔截流量的攻擊者只需出示自己的金鑰即可。

TLS 1.3 握手,逐步解析

與 TLS 1.2 相比,TLS 1.3 大幅簡化了握手過程。以下是瀏覽器與伺服器之間的流程:

  1. ClientHello——客戶端發送支援的 TLS 版本、加密套件、一個隨機值,以及一個 Diffie-Hellman 群組(例如 X25519)的金鑰分享。
  2. ServerHello——伺服器選擇一個加密套件並發送自己的金鑰分享。雙方現在可以推導出相同的共享密鑰。
  3. 加密擴展與憑證——伺服器發送其憑證鏈,此時已使用推導出的金鑰加密。
  4. Finished——雙方對握手會話記錄發送 MAC,以證明沒有任何竄改。
  5. 應用程式資料——HTTP 請求和回應透過已建立的會話流動。

在 TLS 1.3 中,完整握手只需一個往返,而會話恢復可以達到零往返。TLS 1.2 則需要兩個往返,之後才能傳送任何應用程式資料。

為什麼憑證在金鑰推導之後才發送

在 TLS 1.3 中,憑證是加密的。這意味著被動觀察者無法僅從憑證看出客戶端正在造訪哪個網域,從而減少資訊洩漏。這也意味著那些預期在第一個封包中看到明文憑證的除錯工具會感到困惑。

對稱與非對稱加密

一個常見的誤解是 HTTPS 使用伺服器的公開金鑰加密所有內容。事實並非如此。非對稱密碼學速度慢且受大小限制;它僅用於建立共享密鑰。

階段密碼學目的
金鑰交換非對稱(ECDHE)在不發送共享密鑰的情況下達成協議
認證非對稱簽章證明伺服器擁有憑證金鑰
大量資料對稱(AES-GCM 或 ChaCha20-Poly1305)為 HTTP 流量提供快速加密與完整性

Diffie-Hellman 金鑰交換具有一個稱為前向保密的寶貴特性:即使伺服器的私鑰日後洩漏,過去記錄的會話也無法被解密,因為會話金鑰從未從該長期金鑰推導而來。

憑證裡面有什麼

X.509 憑證將公開金鑰綁定到網域名稱。它包含:

瀏覽器信任一組固定的根憑證授權單位。你的伺服器發送一個中繼憑證,瀏覽器則從你的葉憑證向上建立一條鏈,直到受信任的根憑證。如果缺少中繼憑證,桌面瀏覽器可能仍能運作,因為它們會快取中繼憑證,而行動客戶端和命令列工具則會失敗。這是生產環境中最常見的 TLS 錯誤。

實用除錯步驟

當 HTTPS 行為異常時,由外而內逐步檢查。

  1. 檢查憑證鏈:使用 openssl s_client -connect example.com:443 -servername example.com -showcerts。確認伺服器發送完整的鏈,而不僅僅是葉憑證。
  2. 檢查到期日——過期的憑證會導致硬性失敗,沒有變通辦法。
  3. 檢查主機名稱——SAN 列表必須包含客戶端請求的確切主機名稱,包括任何 www 前綴。
  4. 檢查協定版本——如果舊版客戶端僅支援 TLS 1.0,而你的伺服器要求 TLS 1.2+,握手會在 HTTP 之前就失敗。
  5. 檢查重新導向——從 HTTPS 重新導向到 HTTP 再導回會造成迴圈;應在伺服器配置中修正,而非應用程式碼中。
# 檢查憑證鏈和協商後的協定
openssl s_client -connect example.com:443 \
  -servername example.com -showcerts < /dev/null 2>&1 | \
  openssl x509 -noout -subject -issuer -dates

# 測試特定的 TLS 版本
openssl s_client -connect example.com:443 -tls1_2 < /dev/null

在 Nginx 中,ssl_certificate 指令應指向一個檔案,其中包含葉憑證,後面接著中繼憑證,順序就是如此。以錯誤的順序串接它們會產生難以察覺的鏈錯誤。

HSTS 與設定錯誤的代價

HTTP 嚴格傳輸安全性(HSTS)告訴瀏覽器在給定期間內對某個網域使用 HTTPS。它很強大且不留餘地:一旦瀏覽器看到較長的 max-age,即使你之後在伺服器上停用 HTTPS,它也會拒絕純 HTTP。

從較短的 max-age 開始,確認一切正常後再增加。只有在每個子網域都提供有效的 HTTPS 後,才加入 includeSubDomains。預載幾乎是永久性的——只有在你確定時才請求。

常見錯誤設定

將憑證續約視為部署管道,而非行事曆提醒。如果續約需要人工介入,它最終會在最糟糕的時刻失敗。

常見問題

HTTPS 會加密我造訪的網域名稱嗎?

網域會出現在 TLS SNI 擴展中,通常在網路上是可見的。路徑和查詢字串是加密的,但網路觀察者通常可以看到你連線到哪個主機。

為什麼我的網站在瀏覽器中正常,但在 curl 或行動應用程式中失敗?

幾乎總是缺少中繼憑證。瀏覽器通常會快取先前造訪的中繼憑證,而 curl 和許多行動 HTTP 堆疊要求伺服器發送完整的鏈。

TLS 1.3 一定比 TLS 1.2 好嗎?

對於現代客戶端,是的——更少的往返、更小的加密套件集,且預設提供前向保密。僅在你仍服務無法協商 1.3 的客戶端時,才保持 TLS 1.2 啟用。

當你需要檢查終止 TLS 的伺服器日誌時,快速瀏覽 Nginx 日誌分析器 可以幫助你在握手失敗、重新導向迴圈和不尋常的客戶端行為變成故障之前發現它們。