憑證鏈與中繼憑證原理解析

Certificate Chain and Intermediate CA Explained

在 SSL/TLS 憑證的世界中,憑證鏈(Certificate Chain)是確保安全通訊的關鍵機制。本文將深入解析憑證鏈的運作原理、根憑證與中繼憑證的關係,以及常見問題的排解方法。

憑證鏈概念

什麼是憑證鏈?

憑證鏈是一系列數位憑證的連結,從終端實體憑證(End Entity Certificate,即您的伺服器憑證)一直延伸到受信任的根憑證授權中心(Root CA)。這條鏈建立了一條信任路徑,讓用戶端能夠驗證伺服器憑證的真實性。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
憑證鏈結構:

+---------------------------+
|     終端實體憑證          |  ← 您的網站憑證(example.com)
|   (End Entity Cert)       |
+-----------+---------------+
            |
            | 由中繼 CA 簽發
+---------------------------+
|     中繼 CA 憑證          |  ← 中繼憑證授權中心
|   (Intermediate CA)       |
+-----------+---------------+
            |
            | 由根 CA 簽發
+---------------------------+
|     根 CA 憑證            |  ← 自簽憑證,預裝於作業系統/瀏覽器
|   (Root CA)               |
+---------------------------+
            |
      信任錨點(Trust Anchor)

為什麼需要憑證鏈?

憑證鏈的設計解決了以下重要問題:

  1. 安全性分層:根 CA 的私鑰極為重要,將其離線保存可降低被盜用的風險
  2. 靈活性:中繼 CA 可以針對不同用途簽發不同類型的憑證
  3. 可擴展性:允許建立多層次的 CA 架構以應對大規模憑證簽發需求
  4. 風險隔離:若中繼 CA 遭到入侵,只需撤銷該中繼 CA,不影響根 CA
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
信任模型比較:

直接簽發模式(不建議):
+--------+     直接簽發     +--------+
| 根 CA  | ---------------→ | 伺服器 |
+--------+                  +--------+
    高風險:根 CA 頻繁使用

階層式模式(推薦):
+--------+                  +--------+
| 根 CA  | ----離線保存--→ | 中繼 CA | ---→ | 伺服器 |
+--------+                  +--------+       +--------+
    ↑                           ↑
    低風險                    日常操作

根憑證與中繼憑證

根憑證(Root Certificate)

根憑證是憑證鏈的起點,具有以下特性:

  • 自簽憑證:由自己簽發給自己
  • 預先安裝:內建於作業系統、瀏覽器和其他應用程式中
  • 最高信任:作為信任的起點(Trust Anchor)
  • 長有效期:通常有效期為 20-30 年
  • 離線保存:私鑰存放於高度安全的離線環境(如 HSM)
1
2
3
4
5
6
7
8
# 檢視根憑證資訊
openssl x509 -in rootCA.crt -text -noout

# 範例輸出(自簽憑證的特徵):
# Issuer: CN = Root CA           ← 簽發者
# Subject: CN = Root CA          ← 主體(與簽發者相同)
# X509v3 Basic Constraints: critical
#     CA:TRUE                    ← 表示這是 CA 憑證

中繼憑證(Intermediate Certificate)

中繼憑證位於根憑證和終端實體憑證之間:

  • 由上層 CA 簽發:由根 CA 或上層中繼 CA 簽發
  • 可簽發憑證:具有簽發下層憑證的能力
  • 線上使用:用於日常的憑證簽發作業
  • 中等有效期:通常有效期為 5-10 年
  • 可被撤銷:若遭入侵可被撤銷而不影響根 CA
1
2
3
4
5
6
7
8
# 檢視中繼憑證資訊
openssl x509 -in intermediateCA.crt -text -noout

# 範例輸出(中繼憑證的特徵):
# Issuer: CN = Root CA           ← 由根 CA 簽發
# Subject: CN = Intermediate CA  ← 中繼 CA 的名稱
# X509v3 Basic Constraints: critical
#     CA:TRUE, pathlen:0         ← CA 憑證,pathlen 限制層級

終端實體憑證(End Entity Certificate)

終端實體憑證是實際用於伺服器或用戶端的憑證:

  • 由中繼 CA 簽發:不能自己簽發憑證
  • 不具 CA 能力:無法簽發其他憑證
  • 短有效期:通常為 1 年(最長 398 天)
  • 包含服務資訊:如網域名稱、組織資訊等
1
2
3
4
5
6
7
8
# 檢視終端實體憑證
openssl x509 -in server.crt -text -noout

# 範例輸出:
# Issuer: CN = Intermediate CA   ← 由中繼 CA 簽發
# Subject: CN = www.example.com  ← 網站網域名稱
# X509v3 Basic Constraints: critical
#     CA:FALSE                   ← 非 CA 憑證

憑證層級比較

特性根憑證中繼憑證終端實體憑證
自簽
CA 能力
有效期20-30 年5-10 年1 年
儲存方式離線 HSM線上 HSM伺服器
預裝於系統
可被撤銷困難可以可以

驗證流程

完整驗證過程

當用戶端(如瀏覽器)連接到 HTTPS 網站時,會進行以下驗證流程:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
用戶端驗證憑證鏈流程:

第一步:接收憑證
+----------+                           +----------+
| 瀏覽器   | ←---- 傳送憑證鏈 -------- | 伺服器   |
+----------+                           +----------+
     |
     | 收到:伺服器憑證 + 中繼憑證
第二步:建立憑證鏈
+------------------+
| 1. 伺服器憑證    |
| 2. 中繼 CA 憑證  |
| 3. 根 CA 憑證    | ← 從本地信任存放區取得
+------------------+
     |
第三步:逐層驗證
+--------------------------------------------------+
| 3.1 驗證伺服器憑證                               |
|     - 簽章驗證:使用中繼 CA 公鑰驗證             |
|     - 有效期檢查:確認在有效期內                 |
|     - 網域匹配:確認 CN/SAN 與網址相符           |
|     - 撤銷檢查:透過 CRL/OCSP 確認未被撤銷       |
+--------------------------------------------------+
     |
+--------------------------------------------------+
| 3.2 驗證中繼 CA 憑證                             |
|     - 簽章驗證:使用根 CA 公鑰驗證               |
|     - 有效期檢查:確認在有效期內                 |
|     - CA 權限:確認具有簽發憑證的權限            |
|     - 撤銷檢查:確認未被撤銷                     |
+--------------------------------------------------+
     |
+--------------------------------------------------+
| 3.3 驗證根 CA 憑證                               |
|     - 信任檢查:確認存在於本地信任存放區         |
|     - 自簽驗證:使用自己的公鑰驗證簽章           |
+--------------------------------------------------+
     |
第四步:驗證結果
+------------------+
| ✓ 憑證鏈完整     |
| ✓ 所有驗證通過   |
| → 建立安全連線   |
+------------------+

使用 OpenSSL 驗證憑證鏈

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 下載網站的憑證鏈
openssl s_client -connect example.com:443 -showcerts

# 驗證憑證鏈完整性
openssl verify -CAfile ca-bundle.crt server.crt

# 分層驗證(指定中繼憑證)
openssl verify -CAfile rootCA.crt -untrusted intermediateCA.crt server.crt

# 詳細驗證輸出
openssl verify -verbose -CAfile rootCA.crt -untrusted intermediateCA.crt server.crt

驗證憑證鏈的腳本範例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash
# verify-chain.sh - 驗證憑證鏈完整性

DOMAIN=$1
PORT=${2:-443}

echo "=== 驗證 $DOMAIN 的憑證鏈 ==="

# 取得憑證資訊
echo -e "\n[1] 取得憑證鏈..."
echo | openssl s_client -connect "$DOMAIN:$PORT" -servername "$DOMAIN" 2>/dev/null | \
    openssl x509 -noout -subject -issuer -dates

# 顯示完整憑證鏈
echo -e "\n[2] 憑證鏈結構..."
echo | openssl s_client -connect "$DOMAIN:$PORT" -servername "$DOMAIN" 2>/dev/null | \
    grep -E "^( [0-9]|Certificate chain)"

# 驗證憑證鏈
echo -e "\n[3] 驗證結果..."
echo | openssl s_client -connect "$DOMAIN:$PORT" -servername "$DOMAIN" 2>/dev/null | \
    grep "Verify return code"

常見問題與排解

問題一:憑證鏈不完整

症狀:

  • 瀏覽器顯示「憑證不受信任」錯誤
  • 某些用戶端可以連線,某些無法
  • 使用 openssl 驗證時顯示「unable to get local issuer certificate」
1
2
錯誤訊息範例:
SSL certificate problem: unable to get local issuer certificate

原因:

  • 伺服器未正確設定中繼憑證
  • 憑證鏈順序錯誤

解決方案:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 檢查伺服器憑證鏈
openssl s_client -connect example.com:443 -showcerts

# 正確的憑證鏈應包含:
# - Certificate 0: 伺服器憑證
# - Certificate 1: 中繼 CA 憑證
# (根憑證通常不需要傳送)

# 合併憑證建立完整的憑證鏈檔案
cat server.crt intermediate.crt > fullchain.crt

問題二:憑證鏈順序錯誤

症狀:

  • 部分瀏覽器或程式無法驗證憑證
  • SSL Labs 測試顯示 “Chain issues: Incorrect order”

正確順序:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
正確的憑證鏈順序(由上到下):

1. 伺服器憑證(終端實體憑證)
2. 中繼 CA 憑證(最接近伺服器的)
3. 中繼 CA 憑證(較接近根 CA 的)
4. 根 CA 憑證(可選,通常不包含)

錯誤示範(順序顛倒):
1. 中繼 CA 憑證
2. 伺服器憑證

解決方案:

1
2
3
4
5
6
7
# 檢查並修正憑證順序
# 使用 cat 按正確順序合併
cat server.crt intermediate1.crt intermediate2.crt > fullchain.crt

# 驗證合併後的憑證鏈
openssl crl2pkcs7 -nocrl -certfile fullchain.crt | \
    openssl pkcs7 -print_certs -noout

問題三:中繼憑證過期

症狀:

  • 伺服器憑證有效但仍顯示錯誤
  • 錯誤訊息提到 “certificate has expired”

檢查方法:

1
2
3
4
5
# 檢查所有憑證的有效期
for cert in server.crt intermediate.crt root.crt; do
    echo "=== $cert ==="
    openssl x509 -in "$cert" -noout -subject -dates
done

解決方案:

  • 從 CA 取得新的中繼憑證
  • 重新設定伺服器憑證鏈

問題四:根憑證未受信任

症狀:

  • 在特定系統或瀏覽器上無法驗證
  • 錯誤訊息:“certificate signed by unknown authority”

原因:

  • 使用私有 CA 簽發的憑證
  • 作業系統或瀏覽器的信任存放區未更新
  • 使用較新的根憑證(尚未廣泛分發)

解決方案:

1
2
3
4
5
6
7
8
9
# 檢查系統的信任存放區(Ubuntu/Debian)
ls /etc/ssl/certs/

# 更新信任存放區
sudo update-ca-certificates

# 手動添加根憑證
sudo cp custom-root-ca.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates

問題五:憑證與私鑰不匹配

症狀:

  • 伺服器啟動時報錯
  • 錯誤訊息:“key values mismatch”

檢查方法:

1
2
3
4
5
# 比較憑證和私鑰的模數(modulus)
openssl x509 -in server.crt -noout -modulus | openssl md5
openssl rsa -in server.key -noout -modulus | openssl md5

# 兩者的 MD5 值應該相同

問題排解流程圖

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
SSL/TLS 憑證問題排解流程:

開始排解
    |
    v
[檢查憑證是否過期] --是--> 更新憑證
    |
    v
[檢查憑證鏈是否完整] --否--> 添加缺少的中繼憑證
    |
    v
[檢查憑證順序是否正確] --否--> 重新排列憑證順序
    |
    v
[檢查私鑰是否匹配] --否--> 使用正確的私鑰
    |
    v
[檢查網域名稱是否匹配] --否--> 申請正確的憑證
    |
    v
[檢查根憑證是否受信任] --否--> 更新信任存放區或使用受信任的 CA
    |
    v
問題解決

設定範例

Nginx 憑證鏈設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# /etc/nginx/sites-available/example.com

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

    # 憑證鏈檔案(包含伺服器憑證 + 中繼憑證)
    ssl_certificate /etc/nginx/ssl/fullchain.pem;

    # 私鑰檔案
    ssl_certificate_key /etc/nginx/ssl/privkey.pem;

    # SSL 設定優化
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;

    # OCSP Stapling(憑證狀態查詢優化)
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/nginx/ssl/chain.pem;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;

    # 其他設定...
    root /var/www/example.com;
    index index.html;
}

Apache 憑證鏈設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# /etc/apache2/sites-available/example.com-ssl.conf

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com

    # 伺服器憑證
    SSLCertificateFile /etc/ssl/certs/server.crt

    # 私鑰
    SSLCertificateKeyFile /etc/ssl/private/server.key

    # 中繼憑證鏈
    SSLCertificateChainFile /etc/ssl/certs/intermediate.crt

    # 或使用合併的憑證鏈(Apache 2.4.8+)
    # SSLCertificateFile /etc/ssl/certs/fullchain.crt

    # SSL 設定
    SSLEngine on
    SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
    SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
    SSLHonorCipherOrder off

    # OCSP Stapling
    SSLUseStapling on
    SSLStaplingResponderTimeout 5
    SSLStaplingReturnResponderErrors off

    DocumentRoot /var/www/example.com
</VirtualHost>

# OCSP Stapling Cache(需放在 VirtualHost 外)
SSLStaplingCache shmcb:/var/run/ocsp(128000)

建立完整憑證鏈檔案

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/bin/bash
# create-fullchain.sh - 建立完整的憑證鏈檔案

# 憑證檔案路徑
SERVER_CERT="server.crt"
INTERMEDIATE_CERT="intermediate.crt"
ROOT_CERT="root.crt"  # 可選
OUTPUT_FILE="fullchain.crt"

echo "建立憑證鏈檔案..."

# 合併憑證(正確順序)
cat "$SERVER_CERT" > "$OUTPUT_FILE"
cat "$INTERMEDIATE_CERT" >> "$OUTPUT_FILE"
# cat "$ROOT_CERT" >> "$OUTPUT_FILE"  # 根憑證通常不需要

echo "憑證鏈已建立:$OUTPUT_FILE"

# 驗證憑證鏈
echo -e "\n驗證憑證鏈..."
openssl verify -CAfile "$ROOT_CERT" -untrusted "$INTERMEDIATE_CERT" "$SERVER_CERT"

# 顯示憑證鏈內容
echo -e "\n憑證鏈內容:"
openssl crl2pkcs7 -nocrl -certfile "$OUTPUT_FILE" | \
    openssl pkcs7 -print_certs -noout | \
    grep -E "(subject|issuer)="

Let’s Encrypt 憑證鏈

使用 Certbot 取得的 Let’s Encrypt 憑證會自動產生正確的憑證鏈:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Let's Encrypt 憑證檔案結構
/etc/letsencrypt/live/example.com/
├── cert.pem       # 伺服器憑證
├── chain.pem      # 中繼憑證鏈
├── fullchain.pem  # 完整憑證鏈(cert.pem + chain.pem)
└── privkey.pem    # 私鑰

# Nginx 設定(使用 Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

驗證設定是否正確

1
2
3
4
5
6
7
8
9
# 使用 OpenSSL 測試連線
openssl s_client -connect example.com:443 -servername example.com

# 使用 curl 測試
curl -vI https://example.com

# 線上工具
# - SSL Labs: https://www.ssllabs.com/ssltest/
# - SSL Checker: https://www.sslshopper.com/ssl-checker.html

總結

憑證鏈是 SSL/TLS 安全通訊的核心機制,正確理解和設定憑證鏈對於維護網站安全至關重要。

重點回顧:

  1. 憑證鏈結構:終端實體憑證 → 中繼 CA → 根 CA
  2. 根憑證:自簽、預裝於系統、離線保存
  3. 中繼憑證:由上層 CA 簽發、日常簽發作業使用
  4. 驗證流程:逐層驗證簽章、有效期、撤銷狀態
  5. 常見問題:憑證鏈不完整、順序錯誤、憑證過期

最佳實務:

  • 確保伺服器傳送完整的憑證鏈(包含中繼憑證)
  • 使用正確的憑證順序(伺服器憑證在前)
  • 啟用 OCSP Stapling 提升效能
  • 定期監控憑證有效期
  • 使用 SSL Labs 等工具定期檢測設定

參考資料

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy