目錄

SSL/TLS 基礎了解跟應用

正文

先看相關的影片了解 HTTPS 怎麼用 TLS/SSL 加密的。

  • 非對稱加密:伺服器有一組私鑰和公鑰,對方可以用公鑰加密,但一定要用你的私鑰才能解密
  • CA 憑證:伺服器會有一個,由第三方認證,上面有公鑰和私鑰

CA 是為了確定你是跟真的那個網站做連線。

TLS 1.2 加密步驟:

  1. Client Hello
    • Client 生成隨機數 A (Client Random)
    • 告訴 Server 我支援這些加密套件
  2. Server Hello,
    • Server 生成隨機數 B (Server Random)
    • Server 決定:「好,我們用 TLS_RSA_WITH_AES_256… 這個套件。」
  3. Server Certificate, Server 給證書,瀏覽器會根據自己的證書信任列表來確定伺服器是否可信,Client 從憑證中取出 Server 的「公鑰」
    • Server Key Exchange 把公鑰給客戶端
  4. Server Hello Down
  5. Client Key Exchange
    • Client 生成一個 隨機數 C (Pre-Master Secret, 預主密鑰)
    • Client 用剛才拿到的 Server 公鑰,把這個隨機數 C 加密
  6. 生成 Session Key: 現在雙方手裡都有:隨機數 A、隨機數 B、預主密鑰 C。雙方用同樣的演算法算出 Master Secret,再衍生出 Session Key
  7. Change Cipher Spec: Client 告訴 Server:「注意囉!下一條訊息開始,我要用 Session Key 加密了。」
  8. Finished (Encrypted Handshake Message):
    • Client 把剛才所有握手過程的 log 用 Session Key 加密發過去,驗證連線
    • Server 也做一樣的事(Change Cipher Spec -> Finished)

關鍵是最後使用第一隨機數、第二隨機數、第三隨機數 (預主密鑰) 三個就可以得到整個 session key。之後的訊息都用非對稱加密。

CA 憑證

在前面第三步驟,憑證上面有公鑰,所以要怎麼確定那個公鑰是真的小明的公鑰

假設小明要申請一張憑證,小明會準備一份文件(CSR),上面寫著:

小明把這份文件傳給 CA(例如 DigiCert)。

DigiCert 收到文件,確認 Google 真的是這網域的主人後,就要用 非對稱加密 來蓋章了。

  1. 算出指紋 (Hash) CA 把 Google 的文件丟進 SHA-256 演算法,算出一個短短的摘要(Hash)
  2. 用 CA 私鑰加密 (Sign) 這就是關鍵!CA 拿出自己絕對保密、只有它擁有的私鑰,對這個 Hash 值進行加密

CA 把這段「亂碼簽名」貼在 Google 文件的最下面,這張紙現在正式成為 「憑證 (Certificate)」。

瀏覽器會有自己的證書信任列表,這個列表並不是瀏覽器去網路上隨便抓的,而是預先安裝在你電腦或瀏覽器裡的,所以不會被偽造。可以用那個公鑰證明真的 CA 證書不是偽造的。

信息

這世界上只有少數幾家巨頭有權力決定誰可以進入這個「信任名單」。主要分為兩大派系:

  1. OS 層面
    • Microsoft (Windows): Windows 有自己的 Microsoft Trusted Root Program
    • Apple (macOS/iOS): Apple 有自己的 Root Certificate Program
    • Linux: 通常由發行版維護者(如 Debian/Ubuntu)包裝 ca-certificates 套件,來源通常參考 Mozilla
  2. 瀏覽器層面
    • Mozilla Firefox: 它不信任作業系統,它維護自己的 Mozilla Root Store(這是開源界公認的黃金標準)
    • Chrome: 以前是用作業系統的(Windows 上用 Microsoft 的,Mac 上用 Apple 的),但現在 Chrome 也開始推行自己的 Chrome Root Program 以統一安全性。

CA 如何進入這個列表?

這是一個極度嚴格的法律與稽核過程。 DigiCert、GlobalSign 這些 CA 公司,每年必須花大錢請第三方審計(WebTrust 或 ETSI 標準),證明他們的私鑰保管極度安全(通常在軍用級 HSM 硬體中,且有嚴格的門禁與流程)。通過審計後,微軟或 Apple 才會在下一次系統更新時,把這家 CA 的公鑰放進你的電腦裡

就算真的有人偷走那個憑證,因為證書是公開的,大家都可以有,但瀏覽器發現,「好,那憑證上面寫 Google 的公鑰是 Google_Pub_Key。現在請你用對應的私鑰加密一段訊息給我看看。」

但最後駭客只有 Google 的憑證(公開的),沒有 Google 的私鑰(私密的)。駭客無法完成後續的握手。

mTLS

雙向認證,多了讓客戶端送 CA 憑證的步驟,客戶端會拿私鑰在文件上蓋章(加密/簽署),全世界的人都可以拿我的公鑰來檢查這個印章是不是真的(解密/驗證),所以就知道你是真的某個信任的客戶端 (有客戶端的 CA),跟之前的 TLS 加密相反,這邊是用私鑰加密,公鑰解密。

在 TLS 握手時,Client 要證明身份,它會對「之前的握手紀錄(Handshake Messages)」進行簽名。但握手紀錄很長,直接加密太慢。所以 Client 把所有握手紀錄丟進 SHA-256,算出一個短短的摘要(Digest/Hash),例如 A1B2C3D4。Client 用私鑰對這個 A1B2C3D4 進行加密,變成「簽章 (Signature)」。

除了比對 Hash 之外,RSA 簽章標準(如 PKCS#1)還規定了解密出來的資料必須符合特定格式。

步驟如下:

  1. Client Hello
  2. Server Hello
  3. Server Certificate
  4. Server Certificate Request (關鍵差異):伺服器會多傳這一步:「請出示你的證件!而且你的證件必須是由 [List of Trusted CAs] 這些單位簽發的才算數。」
  5. Server Hello Done
  6. Client Certificate:
    • Client 回傳自己的憑證
  7. Client Key Exchange
  8. Certificate Verify:
    • Client 用自己的 Client Private Key 對先前的握手訊息簽名。伺服器用 Client Certificate 裡的公鑰驗證簽名。這證明了「Client 不只撿到了這張憑證,他還真的擁有對應的私鑰」。
場景 驗證對象 (Client) 保護目標 關鍵價值
微服務 另一個程式 (Service A) 內部 API 防止內網橫向移動攻擊 (Lateral Movement)
IoT 硬體設備 雲端數據 綁定實體硬體,防止偽造數據
B2B API 合作夥伴伺服器 金融/個資 比 API Key 更強的身份驗證
企業內網 員工電腦 後台系統 實踐零信任,取代 VPN,防釣魚
資料庫 應用程式 資料存取權 確保只有授權的 App 能連 DB

Custom Domain CA

當初我自己買了 domain,它也會有 CA,新創的註冊商(如 Porkbun, Namecheap)會直接送你免費的 Let’s Encrypt 憑證,幫你自動續約。

但我給 Cloudflare page 託管,Cloudflare 已經幫你向 Google 或 Let’s Encrypt 申請了一張免費憑證。

在 2015 年以前,SSL 憑證是非常昂貴的(一年要好幾千台幣),因為 CA 需要人工審核你的資料。但後來出現了一個非營利組織打破了這個局面:Let’s Encrypt。

它們發明了一套協議(ACME Protocol),讓機器驗證機器,完全不需要人工介入。既然成本趨近於零,就乾脆免費。

它們的目標是讓全世界 100% 的網站都跑在 HTTPS 上(HTTPS Everywhere),讓網路更安全。

免費憑證只驗證你擁有這個網域(你能控制 DNS),不驗證你這家公司是不是真的存在。所以付費 CA 還是有用,銀行、大型電商 (Amazon, PChome)、政府機關。他們需要證明「我是真的銀行」,而不只是「我有這個網址」。

Cloudflare WAF

你可能想說,WAF 怎麼看到加密的 HTTP 內容,它之所以能過濾 HTTP 內容(Layer 7),是因為它採用了 TLS Termination(TLS 終止) 的代理模式。

當你把網站掛上 Cloudflare (開啟橘色雲朵圖示) 時,DNS 解析出來的 IP 其實是 Cloudflare 的 Edge Server IP,而不是原本的 Origin Server IP。

整個連線被切成了兩段:

  1. 第一段 (Client <-> Cloudflare): 這裡使用的憑證,是 Cloudflare 替該網站簽發的(Universal SSL),或者使用者上傳給 Cloudflare 的,因為 Cloudflare 擁有這段連線的 Private Key,所以它能解密出完整的 HTTP 明文 (Payload)
    • WAF 引擎這時候介入,檢查 URL, Header, Body (例如你的 SQL Injection 或 SBOM 請求)
  2. 第二段 (Cloudflare <-> Origin Server): 如果 WAF 判斷請求是安全的,Cloudflare 會再發起一個新的 TLS 連線到真正的源站伺服器

這就是為什麼你在設定 Cloudflare 時需要經過驗證流程。主要有兩種模式:

  1. 模式 A:Universal SSL (最常見,90% 的網站): 當你在 Cloudflare 後台新增網站時,Cloudflare 會自動向 CA (如 Let’s Encrypt, Google Trust Services) 申請一張憑證,這張憑證的 CN (Common Name) 就是你的網域 example.com
  2. 模式 B:Keyless SSL (銀行、大型企業用): 有些公司基於安全規範,絕對不能把私鑰交給第三方 (包括 Cloudflare)。那 Cloudflare 怎麼解密? 這是一個非常高階的技術,Cloudflare 開發了 Keyless SSL 協定:
    1. Cloudflare Edge 收到 Client 的連線請求。
    2. 到了需要用 Private Key 進行運算(例如簽署或解密 Pre-master secret)的時候,Cloudflare 暫停連線。
    3. Cloudflare 把需要運算的數值,透過一條加密通道傳回企業內部的 Key Server。
    4. 企業的 Key Server 用自家保管的私鑰算出結果,回傳給 Cloudflare。
    5. Cloudflare 拿到結果,繼續完成 TLS Handshake。

即便私鑰不在 Cloudflare 手上,Session Key (對稱金鑰) 依然是在 Cloudflare 端生成的。一旦握手完成,Cloudflare 依然擁有解密後的 Session Key,因此依然看得到明文 HTTP 內容來做 WAF 過濾。

攻擊

DNS Poisoning

以前 HTTP 會受到 DNS 污染攻擊,但有了 TLS 加密,就可以防禦了。

假設駭客成功污染了 DNS,讓你輸入 google.com 時,瀏覽器實際上連線到了「駭客的伺服器 IP」。

  1. 駭客拿不出有效的憑證,當你的瀏覽器發起 Client Hello 後,駭客伺服器必須回傳 Server Certificate。如果駭客回傳他自己生成的憑證,瀏覽器會檢查 CA 信任清單,發現這張憑證不是權威機構簽發的,立刻彈出「您的連線並非安全連線」的紅字警告,阻斷連線。

    或者就算是真正憑證機關審核的,上面的憑證 domain 也不會是 google.com。

    那如果駭客更有本事,他騙過了 CA,讓 CA 以為他是 Google 的主人,並簽發了一張寫著 google.com 的合法憑證給他呢?

    這在過去確實發生過(例如 2011 年的 DigiNotar 事件),但現在我們有 CT 紀錄。

    現代瀏覽器(特別是 Chrome)要求所有 CA 簽發憑證後,必須將簽發紀錄寫入公開的、不可篡改的日誌 (CT Logs)。

    像 Google 或 Cloudflare 這樣的大公司會 24 小時監控這些日誌。如果駭客今天偷偷騙過某家小型 CA 簽發了一張 google.com 的憑證,Google 的監控系統幾分鐘內就會發現:「奇怪,我沒申請這張憑證,為什麼日誌裡多了一張?」隨後,這張憑證會被立刻廢止(Revocation),該 CA 甚至可能被撤銷信任資格。

    或者有 CAA 紀錄,網域擁有者可以在 DNS 中設定 CAA 紀錄,告訴全世界:「我只允許 DigiCert 為我簽發憑證」,其他不允許。

  2. 即便駭客從網路上截獲了 Google 真正的「公開憑證」(因為憑證是公開的),他依然會失敗。

    Client 會用憑證裡的 Google 公鑰 加密一個隨機數(Pre-Master Secret)傳回去。 只有擁有 Google 私鑰的人 才能解密這個隨機數。駭客沒有私鑰,無法解密,就無法算出後續的 Session Key。


知名開源軟體 Notepad++ 遭中國國家級駭客劫持長達六個月:規模堪比 SolarWinds 事件

實際上最近還有跟 TLS 相關的攻擊,主要是攻擊原因是因為:

  1. 攻擊者透過系統漏洞或釣魚,直接拿到了 Notepad++ 官網伺服器的管理權限

  2. 早期版本的 WinGUP(Notepad++ 使用的更新工具叫 WinGUP)使用 HTTP(沒加密、沒身分檢查)

  3. 早期 WinGUP 選擇用自簽憑證

    2015 年 Let’s Encrypt 出現之前,獲取一個受信任的 SSL/TLS 憑證是非常昂貴且麻煩的。 每年規費: 當時一個標準的商用憑證每年可能要花費數百美金,對於一個不收費、靠捐款維持的開源專案(如 Notepad++)來說,是一筆額外的負擔。

    自簽憑證完全免費,且技術上同樣能提供加密功能。當時許多開發者認為:「只要數據有加密,中間人看不見內容就好」,卻忽略了身份驗證 (Authentication) 的重要性。

    在網路安全中,加密通道只是解決了一半的問題(不被偷聽),另一半的問題是:你怎麼確定跟你說話的人真的是他本人?所以才需要 CA,而不是自簽憑證,假設 Notepad++ 官方使用自簽憑證。當你的電腦去下載更新時,駭客攔截了連線,並丟出另一張同樣寫著「Notepad++ Official」的自簽憑證。 因為沒有第三方(CA)來背書,你的電腦無法分辨「這張是作者 Don Ho 簽的」還是「這張是駭客簽的」。