🌿gRPC + Kestrel 自簽憑證完整攻略:從觀念到實戰
前言
這篇文章是我在開發 gRPC + Kestrel 專案時,遇到 SSL 憑證問題後整理的學習筆記。
如果你跟我一樣,正在用 .NET 的 Kestrel 當作 gRPC Server,並且想要啟用 HTTPS 加密連線,那你一定會遇到一個問題:怎麼產生一張測試用的憑證?
這篇文章會從觀念開始講起,一步一步帶你走完整個流程。
目錄
觀念篇:為什麼是 Server 要有憑證?
這是我學習時最容易搞混的地方。
我們直覺會覺得:「我是客戶端 (UI),我要連到伺服器 (Server),應該是我拿出證件證明『我是誰』才對吧?」
但在 HTTPS/TLS 的世界裡,邏輯是反過來的。
詐騙集團 vs. 真銀行
想像你的 UI (前端) 是一輛運鈔車,你的 Server (後端) 是一間銀行金庫。你要把錢 (資料) 運進去。
| 角色 | 比喻 | 驗證目的 |
|---|---|---|
| Server | 銀行金庫 | 出示「營業執照 (憑證)」證明自己是真的銀行 |
| Client | 運鈔車 | 在連線建立後,透過帳號密碼/Token 證明身份 |
運鈔車司機最怕什麼? 怕開錯地方,把錢交給假扮成銀行的詐騙集團!
所以 銀行 (Server) 必須在大門口掛一張「政府核發的營業執照 (憑證)」。運鈔車司機 (UI) 遠遠開過來,先拿望遠鏡看那張執照:「嗯,這是真的銀行,不是假佈景。」確認安全後,運鈔車才敢開過去建立連線。

SSL Handshake 流程
什麼時候 Client 才需要憑證?
如果你有這個疑問,那叫做 雙向驗證 (mTLS, Mutual TLS)。軍方系統或銀行內部核心系統會用這種方式,要求雙方都出示憑證。
但在一般應用程式開發非常少見,因為管理太麻煩了 (每台 Client 電腦都要裝憑證)。
簡單記法: HTTPS 就像是 Server 開了一家店,它要把「營業執照 (憑證)」掛在門口給你看,你才敢進去消費。
工具篇:PowerShell vs. IIS 管理介面
這是一個經典的「CLI (指令列) vs GUI (圖形介面)」的問題。
核心差異比較
| 特性 | PowerShell | IIS 管理介面 |
|---|---|---|
| 精準度 | ⭐⭐⭐⭐⭐ 極高 | ⭐⭐ 低 |
| 自訂功能 | 可自訂過期日 (5年)、多網域 (SAN)、密碼強度 | 幾乎無法自訂 (預設 1 年) |
| 環境需求 | Windows 內建 (不需安裝額外功能) | 必須安裝 IIS (Web Server) 才能用 |
| 自動化 | ✅ 可寫成腳本一鍵執行 | ❌ 必須手動點擊滑鼠 |
| 主要用途 | 開發人員、DevOps 自動化 | 網管人員 (SysAdmin) 快速設定 |
為什麼 IIS 介面不適合 gRPC 專案?
致命傷 A:缺了「主體別名 (SAN)」
- IIS 做出來的: 通常只會設定
Subject = localhost - 現代標準: Chrome 和 .NET Core 預設已經不看 Subject 了,它們看的是 SAN (Subject Alternative Name)
- 結果: gRPC Client 連線時還是噴錯「憑證無效」
PowerShell 指令裡的 -DnsName "localhost", "127.0.0.1" 就是在設定 SAN。
致命傷 B:殺雞焉用牛刀
你的架構是 Kestrel (WinForm 裡面的自宿主 Server)。
為了產生一張憑證,特地去 Windows 功能裡安裝龐大的 IIS (Internet Information Services),這就像為了喝一杯牛奶養了一頭牛。
結論: 現代化的 .NET Core gRPC 跑在 Kestrel 上,PowerShell 是你的唯一正解。
實戰篇:產生測試憑證 (PFX)
第一步:執行 PowerShell 腳本
- 在 Windows 開始選單搜尋 PowerShell
- 右鍵 → 「以系統管理員身分執行」
- 複製下面這整段程式碼,貼進 PowerShell 視窗並按下 Enter
# --- 設定參數區 ---
$pfxPassword = "m1234"
$pfxFileName = "server_cert.pfx"
$friendlyName = "[Dev_Cert_DoNotTrust]"
$outputDir = "C:\Temp\LCerts"
# -----------------
# 1. 建立暫存資料夾
if (!(Test-Path $outputDir)) {
New-Item -ItemType Directory -Path $outputDir | Out-Null
}
$pfxPath = Join-Path $outputDir $pfxFileName
Write-Host "正在製造測試用的營業執照..." -ForegroundColor Cyan
# 2. 產生自簽憑證
$cert = New-SelfSignedCertificate `
-DnsName "localhost", "127.0.0.1" `
-CertStoreLocation "Cert:\CurrentUser\My" `
-FriendlyName $friendlyName `
-KeyExportPolicy Exportable `
-KeySpec KeyExchange `
-NotAfter (Get-Date).AddYears(5)
# 3. 匯出成 .pfx
$passwordSecure = ConvertTo-SecureString $pfxPassword -AsPlainText -Force
Export-PfxCertificate -Cert $cert -FilePath $pfxPath -Password $passwordSecure
# 4. 顯示結果
Write-Host "`n★ 成功!憑證已產生!" -ForegroundColor Green
Write-Host "檔案位置: $pfxPath" -ForegroundColor Yellow
Write-Host "檔案密碼: $pfxPassword" -ForegroundColor Yellow
Write-Host "指紋 (Thumbprint): $($cert.Thumbprint)" -ForegroundColor Magenta
第二步:部署到專案
- 打開你的 Visual Studio 專案資料夾
- 在後端專案裡,建立
Config資料夾 - 把
C:\Temp\Certs\server_cert.pfx複製進去 - 在 Visual Studio 裡:
- 點選
.pfx檔案 - 在「屬性」視窗,找到 「複製到輸出目錄」
- 改為 「如果有更新則複製」
- 點選
第三步:更新設定檔
後端 Config:
UseSsl = true
CertPath = @".\Config\server_cert.pfx"
CertPassword = "m1234"
前端 Config:
UseSsl = true
AllowInsecure = false
Thumbprint = (貼上 PowerShell 顯示的指紋)
前端篇:設定指紋驗證
觀念解鎖:為什麼前端不需要 PFX 檔案?
「PFX 檔案當然有指紋,但前端不需要 PFX 檔案,前端只需要知道那串『指紋號碼』就好。」
想像你是 「演唱會驗票員 (前端 Client)」,而後端 Server 是 「持有 VIP 票的觀眾」:
- 後端 (Server): 手上有 VIP 門票正本 (PFX 檔案)
- 前端 (Client): 手上有主辦單位給的清單,寫著「今天的 VIP 票號碼是 A1B2C3... (指紋)」
當後端走過來出示他的票,你只要看一眼他的票號跟清單一樣,就放行。
實作步驟
找出指紋
如果關掉了 PowerShell 視窗,用這個指令再查一次:
Get-ChildItem -Path Cert:\CurrentUser\My | Where-Object { $_.FriendlyName -like "*LCS*" }
設定前端 Config
打開 ConnectionList.xml:
<ConnectionInfo
Name="Local_Dev_Secure"
Ip="127.0.0.1"
Port="5006"
UseSsl="true"
AllowInsecure="false"
Thumbprint="A1B2C3D4E5F678901234567890ABCDEF12345678" />
| 屬性 | 說明 |
|---|---|
UseSsl="true" |
告訴運鈔車要走 HTTPS 通道 |
AllowInsecure="false" |
告訴運鈔車要嚴格驗證 |
Thumbprint="..." |
告訴運鈔車只准讓拿這張身分證的人進來 |
清理篇:刪除測試憑證
測試完懂得把垃圾帶走,保持開發環境的潔淨,這才是有潔癖的高級工程師該有的素養。
方法一:PowerShell 光速滅證 (推薦)
# --- 設定區 ---
$targetFriendlyName = "[Dev_Cert_DoNotTrust]"
$tempPfxPath = "C:\Temp\Certs\server_cert.pfx"
# --------------
Write-Host "正在搜尋並移除測試憑證..." -ForegroundColor Cyan
# 1. 清除 Windows 憑證存放區
$certs = Get-ChildItem -Path "Cert:\CurrentUser\My" | Where-Object { $_.FriendlyName -eq $targetFriendlyName }
if ($certs) {
foreach ($c in $certs) {
Remove-Item -Path $c.PSPath
Write-Host "✅ 已從 Windows 存放區移除憑證: $($c.Thumbprint)" -ForegroundColor Green
}
} else {
Write-Host "⚠️ 在存放區找不到該憑證" -ForegroundColor Yellow
}
# 2. 清除暫存檔案
if (Test-Path $tempPfxPath) {
Remove-Item -Path $tempPfxPath -Force
Write-Host "✅ 已刪除暫存檔案: $tempPfxPath" -ForegroundColor Green
}
Write-Host "`n電腦回復乾淨狀態!" -ForegroundColor Cyan
方法二:手動介面刪除
- 按下
Win + R,輸入certmgr.msc,按 Enter - 左側展開 「個人 (Personal)」 → 「憑證 (Certificates)」
- 找到「發給」是
localhost,「好記名稱」是[Dev_Cert_DoNotTrust]的那張 - 右鍵 → 刪除
方法三:清理專案裡的殘留
別忘了刪除專案目錄裡的 Config\server_cert.pfx!
PowerShell 腳本只會刪除 C:\Temp 裡的原始檔,不會動專案裡的那份複製品。
總結
| 步驟 | 說明 |
|---|---|
| 1 | 理解憑證是給 Server 用的 |
| 2 | 用 PowerShell 產生自簽憑證 |
| 3 | 把 .pfx 複製到後端專案 |
| 4 | 把指紋貼到前端設定檔 |
| 5 | 測試完記得清理環境 |
現在,你的後端就是一家持有合法 (測試用) 執照的銀行,而你的前端就是拿著正確指紋驗證碼的運鈔車。
按下 F5 啟動吧!
- first edition time: 2026-01-31