SSL 憑證
以前,大家都使用 http 協定傳輸資料,但因為缺乏加密設計,導致資料在傳輸過程中很容易被竊聽和篡改。 為了解決這個問題,SSL(Secure Sockets Layer)被引入了。
SSL 是一種安全協定,最早是由 Netscape 公司開發的,後來 IETF 將 SSL 進行標準化並改名為 TLS(Transport Layer Security)。他使用了複雜的加密算法來保護資料的安全,確保資料在傳輸過程中不被竊聽和篡改。
但若單純使用 SSL/TLS 協定,仍然無法防禦中間人攻擊,因為攻擊者可以冒充伺服器來竊聽和篡改資料。
中間人攻擊:
flowchart LR
A["客戶端"]
M["攻擊者\n偽造雙向身份"]
S["伺服器"]
A<-. "假裝是伺服器\n(使用自己的憑證進行通訊)" .->M
M<-. "假裝是客戶端\n(使用自己的憑證進行通訊)" .->S
style A fill:#EBF3FB,stroke:#85B7EB,color:#0C447C
style M fill:#FCEBEB,stroke:#E24B4A,color:#A32D2D
style S fill:#E1F5EE,stroke:#5DCAA5,color:#085041
為了防中間人攻擊,CA(Certificate Authority)機構被引入了。
CA 是一個受信任的第三方機構,負責簽發和管理 SSL 憑證。簽發 SSL 憑證的過程中,CA 會驗證申請者的身份,確保他們是合法的網站所有者。
當客戶端連接到伺服器時,伺服器會提供 SSL 憑證給客戶端,客戶端會檢查憑證是否由受信任的 CA 簽發,以及憑證是否有效。如果憑證無效或未被信任,客戶端會顯示警告訊息,提醒使用者可能存在安全風險。
如下圖即是瀏覽器對於無效憑證的警告訊息:
憑證是由信任鏈(Chain of Trust)來確保其真實性的。
通常,一個完整的信任鏈包含三個主要的層級:
-
根憑證 (Root Certificate): 由 CA 機構自己簽發給自己,並且預先內建在我們的作業系統或瀏覽器的信任庫中。這代表我們的設備預設且無條件信任這些根 CA。
如下圖中的GTS Root R4 -
中介憑證 (Intermediate Certificate): 為了保護根憑證的私鑰安全 (如果根憑證外洩,後果不堪設想),根 CA 通常不會直接簽發最終的網站憑證,而是將權限授權給中介 CA。中介 CA 就像是橋樑,負責日常的憑證簽發工作。
如下圖中的WE1 -
伺服器憑證 (Server / Leaf Certificate): 最終簽發給網站的憑證。這也就是我們架設網站時需要安裝到伺服器上的那張憑證。
如下圖中的cpp.doong.me
flowchart TD
Root["根憑證 (GTS Root R4)\n預先安裝在作業系統或瀏覽器中"]
Inter["中介憑證 (WE1)\n由根憑證簽署並授權"]
Leaf["伺服器憑證 (cpp.doong.me)\n我的網站所使用的憑證"]
Root --"信任並驗證"--> Inter
Inter --"信任並驗證"--> Leaf
style Root fill:#E1F5EE,stroke:#5DCAA5,color:#085041
style Inter fill:#FFF9C4,stroke:#FBC02D,color:#F57F17
style Leaf fill:#EBF3FB,stroke:#85B7EB,color:#0C447C
SSL 憑證有一個有效期線 (例如上面圖中的憑證會在 2026/8/7 到期),過了這個日期,憑證就會失效,瀏覽器就會顯示警告訊息,提醒使用者可能存在安全風險。
且最近的趨勢是縮短憑證的有效期,以提高安全性。
根據 CAB Forum 的規定,憑證期限縮短規劃如下:
- 至 2026 年 3 月 15 日止,TLS 憑證的最長有效期為 398 天。
- 自 2026 年 3 月 15 日起,TLS 憑證的最長有效期為 200 天。
- 自 2027 年 3 月 15 日起,TLS 憑證的最長有效期為 100 天。
- 自 2029 年 3 月 15 日起,TLS 憑證的最長有效期為 47 天。
這也就意味著傳統的憑證申請流成將被淘汰,全面走向自動化申請。
TLS 握手流程
Section titled “TLS 握手流程”有了憑證之後,客戶端和伺服器是怎麼建立安全連線的呢?這就是 TLS 握手的工作。
目前主流的 TLS 1.3 握手只需要 1-RTT(一次來回),比舊版 TLS 1.2 的 2-RTT 更快:
sequenceDiagram
participant C as 客戶端
participant S as 伺服器
C->>S: ① Client Hello
Note right of C: 支援的加密套件清單、亂數、DH 公鑰
S->>C: ② Server Hello
Note left of S: 選定的加密套件、亂數、DH 公鑰
Note over C,S: 雙方各持對方的 DH 公鑰,計算出相同的 Session Key<br/>(金鑰不透過網路傳遞!)
S->>C: ③ Certificate(伺服器憑證)
S->>C: ④ CertificateVerify(用伺服器私鑰簽名)
S->>C: ⑤ Finished
Note over C: 用 CA 信任鏈驗證憑證合法性<br/>用憑證中的公鑰驗證伺服器簽名
C->>S: ⑥ Finished
Note over C,S: 握手完成,使用 Session Key 加密後續所有資料
整個握手流程有三個核心目標:
- 身份驗證:透過憑證和 CA 信任鏈確認伺服器身份,防止中間人攻擊
- 金鑰交換:使用 Diffie-Hellman(DH) 演算法,讓雙方在不直接傳送密鑰的情況下算出相同的 Session Key
- 資料加密:握手完成後,所有資料都以 Session Key 做對稱加密傳輸,效率遠高於非對稱加密
不過還是有個缺陷,就是 Client Hello 是用明文傳送的,且其中包含 SNI(Server Name Indication),可以讓中間人看出客戶端在連接的網站。
那我們到底要怎麼把 SSL 憑證安裝到我們的網站上呢?
好消息是現在有很多免費的 SSL 憑證提供者,例如 Let’s Encrypt、Google Trust Services 等等,這些提供者都提供了自動化的工具,可以輕鬆地申請和安裝 SSL 憑證。 不像以前憑證都需要付費,還要手動申請和安裝,現在只需要幾行指令就可以完成整個流程。
那他們要怎麼驗證我們是網站的擁有者呢?
Section titled “那他們要怎麼驗證我們是網站的擁有者呢?”我們需要從下面幾種挑戰中選擇一種來完成驗證:
- HTTP-01:在網站上放置一個特定的檔案,讓 CA 來訪問這個檔案來驗證對該域名的控制權。
- DNS-01:在 DNS 記錄中添加一個特定的 TXT 記錄,讓 CA 來查詢這個記錄來驗證對該域名的控制權。
- TLS-ALPN-01:在伺服器上配置一個特定的 TLS 服務,讓 CA 來連接這個服務來驗證對該域名的控制權。
以下以 HTTP-01 為例:
-
我們需要先有一個網域,只有 ip 是無法申請 SSL 憑證的,因為憑證是綁定在網域上的。
-
接著我們需要選擇一個 SSL 憑證提供者,我推薦 Let’s Encrypt,因為它是免費的,而且有很多自動化的工具可以使用。
-
接著我們需要安裝自動化工具,例如 Certbot,來幫助我們自動申請和安裝 SSL 憑證。
Terminal window sudo snap install --classic certbotsudo ln -s /snap/bin/certbot /usr/local/bin/certbot -
申請憑證!
Terminal window sudo certbot certonly --standalone -d yourdomain.com -
測試自動續約(可選)
Terminal window sudo certbot renew --dry-run
或者是我也很推薦直接使用 Caddy 作為反向代理伺服器,因為他內建了自動申請和安裝 SSL 憑證的功能,完全不需要額外的工具和設定,且設定檔也比較簡單。
如果想要快速體驗的話可以把任何網域的 caddydemo 子網域指向 Caddy demo.caddyserver.com,接著直接在瀏覽器打開它,就能親身體驗 Caddy 自動申請 SSL 憑證的高效及便利。
例如:https://caddydemo.doong.me/
夯爆了,用過一次就回不去了。
同場加映:反向代理
Section titled “同場加映:反向代理”雖然我們有了憑證,但要將他套用到我們的網站上是很麻煩的,我們很難直接依靠一個 fastapi、flask 或其他框架的應用程式來處理 SSL/TLS。
因此,我們通常會使用一個反向代理伺服器(例如 Caddy、Nginx、Apache 等等)來處理 SSL/TLS,然後將請求轉發到我們的應用程式上。
反向代理是將本地的 http 服務轉發成外部可連線的 https 服務。此外,反向代理還可以提供負載平衡、緩存、壓縮等功能,提升網站的效能和安全性。
我絕對推薦 Caddy,他的設定檔非常簡單,且自動配置 SSL 憑證的功能真的太方便了,自從我用了 Caddy 後,我再也不用擔心 SSL 憑證的問題了。 Caddy 真的用過就回不去了。
雖然他在極端的高流量情況下可能會有一些性能可能略低於 Nginx,但明顯我不會遇到這麼大的流量。
同場加映:隧道
Section titled “同場加映:隧道”如果沒有自己的伺服器,或者伺服器沒有公開的 IP 地址,那麼就無法直接申請 SSL 憑證了。
不過可以使用一些隧道服務(例如 ngrok、Cloudflare Tunnel 等等)來將本地服務暴露到外部,這些服務也會自動搞定 SSL 憑證。 且這些隧道服務通常也會提供一些額外的功能,例如流量分析、DDoS 防護、訪問控制等等,非常方便。
最推 Cloudflare Tunnel,蠻好用的。 但如果沒有自己的網域,可能只能選擇 ngrok 的免費子網域了,雖然不太好記,但也是一個不錯的選擇。