為什麼要 TLS,只加密不夠嗎
假設你和銀行之間有一個加密通道——但你怎麼知道你連的是真正的銀行,不是一個攻擊者偽裝成銀行,然後用自己的 key 加密?
TLS 解決三件事:
- 加密(Confidentiality):通訊內容不被第三方看到
- 完整性(Integrity):內容不被篡改(MAC)
- 認證(Authentication):確認 server 的身份(certificate)
TLS 握手(簡化版 TLS 1.2)
Client Server
│─── Client Hello ──────────→ │ 支援的 TLS 版本、cipher suites、random number
│ │
│ ←── Server Hello ────────── │ 選定的 cipher suite、random number
│ ←── Certificate ─────────── │ server 的公鑰憑證
│ ←── Server Hello Done ────── │
│ │
│ 驗證憑證 (Certificate Chain) │
│ │
│─── Client Key Exchange ───→ │ 用 server 公鑰加密的 pre-master secret
│─── Change Cipher Spec ────→ │ 接下來用協商的 session key 加密
│─── Finished ──────────────→ │
│ │
│ ←── Change Cipher Spec ──── │
│ ←── Finished ───────────── │
│ │
│════ 加密的應用資料 ══════════ │
TLS 1.3 把握手壓縮到 1 RTT(從 TLS 1.2 的 2 RTT),大幅降低延遲。
Certificate Chain(憑證鏈)
你的瀏覽器為什麼信任 api.example.com 的憑證?
Root CA(瀏覽器內建信任)
└── Intermediate CA
└── api.example.com Certificate
瀏覽器信任一批 Root CA(Let’s Encrypt, DigiCert, Comodo 等)。Root CA 簽發給 Intermediate CA,Intermediate CA 再簽發給你的域名憑證。你的瀏覽器驗證整個鏈都有效,才信任你的 server。
常見的 Certificate Error:
ERR_CERT_AUTHORITY_INVALID:憑證不是受信任的 CA 簽發的(自簽憑證、或 intermediate CA 沒有正確包含在回應裡)ERR_CERT_DATE_INVALID:憑證過期(Let’s Encrypt 憑證 90 天,要自動續期)ERR_CERT_COMMON_NAME_INVALID:域名不符(憑證是example.com但你連到api.example.com,需要 wildcard*.example.com或 SAN)
自簽 vs CA 簽發
CA 簽發(Let’s Encrypt 免費):瀏覽器信任,生產環境用。
自簽憑證:自己當 CA 簽自己的憑證,瀏覽器不信任(顯示警告)。適合:
- 本機開發環境(
mkcert讓本機 CA 被信任) - 服務間的 mTLS(雙方都信任同一個內部 CA)
Cipher Suite
TLS 握手時雙方協商一組加密算法:
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
└─────────────────────────────────────
Key Exchange: ECDHE(提供 Forward Secrecy)
Authentication: RSA
Bulk Encryption: AES-256-GCM
MAC: SHA-384
Forward Secrecy:ECDHE / DHE key exchange 每個 session 生成不同的 session key,即使伺服器私鑰洩漏,過去的通訊也無法被解密——因為 session key 沒有存下來。
TLS 1.3 移除了所有不支援 Forward Secrecy 的 cipher suite,讓 HTTPS 更安全。