CSR 解碼工具

在你的瀏覽器中解碼,不會傳送到任何地方。CSR 與你的私鑰只有一步之遙,因此不該貼進會上傳內容的網頁。本工具不會上傳,也永遠不會要求你的私鑰。

您輸入的內容不會被儲存、記錄或分享。

貼上憑證簽章要求(CSR)或 X.509 憑證,即可讀出其中的內容:主體、別名、金鑰演算法與長度、有效期間、擴充欄位與指紋。所有解碼都在你的瀏覽器中完成,內容不會被上傳。

使用方式

  1. 貼上完整的 PEM 區塊,包含 BEGIN 與 END 兩行。
  2. 檢視解碼後的欄位:主體、SAN、金鑰、有效期間與擴充欄位。
  3. 複製指紋,與你的伺服器或主控台顯示的值比對。

CSR 包含什麼、不包含什麼

憑證簽署要求(CSR)包含三樣東西:你希望憑證上記載的主體名稱、金鑰對中的公開金鑰,以及你要求的擴充欄位,其中最重要的是主體別名(SAN)。CSR 以你的私密金鑰簽署,藉此向憑證機構(CA)證明你確實持有要請他們認證的那把金鑰。

CSR 不包含私密金鑰,也無法從中推導出私密金鑰。這就是為什麼 CSR 不像金鑰那樣是機密,貼到工具裡也算合理。但它也不是毫無資訊:CSR 描述了主機名稱、組織,有時還透露內部命名慣例,所以值得確認你使用的解碼器會不會把它傳到別處。很多解碼器會,因為它們大多是由販售憑證的公司經營的。

也值得知道 CSR 的內容最後保留下來的其實很少。CA 驗證名稱後,會用自己的序號、有效期間、簽發者,以及自己認為該放哪些擴充欄位來簽發憑證。組織與所在地欄位取自 CA 驗證過的紀錄,而不是你輸入的內容。實務上,真正沿用下來的是公開金鑰與名稱。

一般名稱已經過時,SAN 才是關鍵

由於歷史因素,主體的一般名稱(CN)看起來像是標示網站名稱的欄位,但它多年前就不再具有這個作用。Chrome 在 2017 年停止採用 CN,其他瀏覽器隨後跟進,CA/Browser Forum 也要求憑證涵蓋的每個名稱都必須列在 SAN 擴充欄位中。只有 CN 沒有 SAN 的憑證,不論 CN 寫了什麼,都會被目前所有的用戶端拒絕。

因此 SAN 清單才是應該最先查看的欄位,而且必須包含憑證要服務的每一個主機名稱;如果除了 www 之外也用裸網域提供服務,裸網域也要列入。萬用字元只涵蓋一層標籤,所以 *.example.com 符合 www.example.com,但不符合 example.com,也不符合 a.b.example.com。

在 CSR 中,SAN 很容易被漏看,不少解碼器也確實漏掉了。在已簽發的憑證裡,SAN 是最上層的擴充欄位;在要求中,它則包在 extensionRequest 屬性裡,深了兩層。本工具會到正確的位置讀取,所以如果這裡顯示清單為空,就代表這份 CSR 真的沒有 SAN,送出之前應該先修正。

如何解讀憑證

除了主體與有效期間之外,還有幾個擴充欄位決定了憑證能做什麼,有意思的答案通常就在這裡。

基本限制(Basic Constraints)說明這是否為 CA 憑證。終端憑證上出現 CA:TRUE 是嚴重的誤發;伺服器憑證應該顯示 CA:FALSE。金鑰用途與延伸金鑰用途則限縮金鑰可用的範圍:TLS 伺服器是 serverAuth,雙向 TLS 是 clientAuth。缺少用戶端所預期用途的憑證,即使其他一切正確也會被拒絕。

授權資訊存取(AIA)包含簽發者憑證的網址,部分用戶端會藉此補齊不完整的憑證鏈,另外還有 OCSP 回應伺服器的網址。憑證透明度時間戳記證明憑證已公開登錄,這是現在瀏覽器的要求。授權金鑰識別碼與主體金鑰識別碼,才是建立憑證鏈時實際比對的依據,比用肉眼比較簽發者與主體字串可靠得多。

指紋請優先使用 SHA-256;之所以也顯示 SHA-1,只是因為許多管理主控台與憑證釘選設定仍會列出它。兩者都是對 DER 編碼計算,結果與 openssl 輸出一致。

憑證鏈問題

最常見的憑證故障,問題往往不在憑證本身,而在憑證鏈:伺服器在桌面瀏覽器正常,在 curl、行動 App 或 JVM 用戶端卻失敗。

伺服器必須提供自己的憑證,以及到根憑證為止(不含根憑證)的所有中繼憑證。瀏覽器常會透過 AIA 網址自動抓取缺少的中繼憑證,或使用從其他網站快取的版本來掩蓋問題,所以用 Chrome 測試的人看不到問題,其他所有用戶端卻會立刻失敗。連根憑證一起送出雖然無害,但沒有意義,因為用戶端要不是早已擁有,就是本來就不信任它。

在傳統 TLS 憑證鏈中順序很重要:先放終端憑證,再依序放各層簽發者。把完整憑證鏈貼到這裡,會依照貼上的順序分別解碼每個區塊,缺少或放錯位置的中繼憑證就會一目了然。請逐一比對每張憑證的簽發者與下一張的主體,也別忘了檢查中繼憑證的到期日;中繼憑證同樣會過期,而過期的中繼憑證會讓完全有效的終端憑證無法使用。

產生請求,以及背後那把金鑰

CSR 一定是和金鑰對一起產生的,而真正重要的是金鑰。慣用的指令會一次產生兩者:openssl req -new -newkey rsa:2048 -nodes -keyout example.key -out example.csr。其中 -nodes 這個旗標會讓金鑰不加密,這正是網頁伺服器啟動時不會跳出密語提示所需要的,也正因如此,那個檔案必須設成只有服務帳號讀得到。

就相容性而言,2048 位元的 RSA 仍然是安全的預設選擇。使用 P-256 曲線的 ECDSA 能以小得多的金鑰和更快的交握達到同等安全性,可用 openssl ecparam -genkey -name prime256v1 產生,而且目前所有瀏覽器都接受。只有部分老舊的中介設備與舊版 Java 用戶端不支援,這也是如今還選擇 RSA 的唯一實質理由。

subject alternative name 是大家最常漏掉的欄位,因為互動式提示根本不會問到它。它必須透過設定檔或 -addext 旗標提供,例如 -addext "subjectAltName=DNS:example.com,DNS:www.example.com"。缺少它的請求會被拒絕,或者更糟:真的簽發出一張沒有任何瀏覽器會接受的憑證。

自動化簽發改變了整套流程

產生 CSR、貼進廠商的入口網站、等待、下載憑證、安裝、明年再來一次,這套手動循環如今已是例外。Let's Encrypt 在 2016 年推出的 ACME 協定把整個交換過程自動化:用戶端證明自己控制該網域、送出 CSR、收到憑證,通常在幾秒內完成,全程不需要人介入。

證明網域控制權有三種方式。HTTP-01 在一個 well-known 路徑上提供一組 token,前提是連得到 80 埠。DNS-01 發布一筆 TXT 記錄,它是唯一能簽發萬用字元憑證的方法,也是唯一適用於沒有公開網頁伺服器的主機的方法。TLS-ALPN-01 則在 443 埠回應一種特殊的交握,適合只開放該埠的環境。

以這種方式簽發的憑證,有效期刻意設計為 90 天,理由是較短的壽命能限制金鑰外洩造成的損害,並迫使續期流程走向自動化,而不是靠人記得。用戶端大約在壽命的三分之二時進行續期,因此就算失敗,也還有時間在任何東西過期之前被發現。

驗證等級、萬用字元,以及憑證到底證明了什麼

網域驗證只能證明申請憑證的人在那個當下控制著該網域。組織驗證與延伸驗證則額外查核背後的法人實體,這些資訊會出現在所簽發憑證的主體欄位中。瀏覽器早在多年前就不再給 EV 任何特殊的介面待遇,所以今天的實際差別多半落在合約與流程層面,而不是訪客看得到的東西。

萬用字元只涵蓋恰好一層標籤:*.example.com 能匹配 www 和 api,但匹配不到 example.com 本身,也匹配不到 a.b.example.com。這就是為什麼大多數萬用字元憑證會把裸網域另外列為一個 SAN。萬用字元也會讓風險集中,因為一把金鑰外洩就影響該名稱底下的每一台主機,而且沒有 DNS 控制權根本無法簽發。

以上這些都沒有說明這個網站值不值得信任。憑證代表的是連線有加密、名稱有對上;它從來就不代表經營者誠實。釣魚網站持有有效憑證是家常便飯,這正是瀏覽器介面不再暗示相反意思的原因。

過期是維運問題,不是憑證問題

憑證過期造成的服務中斷常見到足以自成一類:它曾經弄垮支付網路、行動電信業者與雲端管理主控台。憑證完全照著設計去做它該做的事,出問題的是圍繞著它的流程。

監控應該針對剩餘天數發出告警,而不是等到失敗才告警,而且門檻要拉得夠早,讓人來得及處理:90 天的憑證抓兩週,一年期的憑證抓一個月。請監控端點而不是檔案,因為真正有影響的是伺服器實際送出的那一張憑證;同時也要檢查中繼憑證,它們一樣會過期,而過期的中繼憑證會讓一張完全正常的終端憑證失效。

憑證透明度記錄等於送你一份免費的清單。所有受公開信任的憑證都會被記錄下來,因此搜尋你的網域就能看到目前存在哪些憑證,包括組織裡其他人簽發後忘了告訴你的那些。

出狀況時怎麼讀憑證鏈

最有用的單一指令是 openssl s_client -connect host:443 -servername host,它顯示的是伺服器實際送出的內容,而不是你設定檔裡寫的內容。它印出的憑證鏈應該從終端憑證開始,接著依序是每一層簽發者,而且每張憑證的 issuer 那一行都應該對得上下一張憑證的 subject 那一行。

缺少中繼憑證是最經典的故障,而且在桌面瀏覽器上看不出來,因為瀏覽器會自行去抓缺少的憑證,或早就從別的網站快取了它。curl、行動應用程式與 JVM 用戶端都不會這麼做,於是症狀就變成:測試的人自己看一切正常,卻有相當大比例的真實流量連不上。

如果憑證鏈看起來沒問題、連線卻還是失敗,接下來要檢查的是金鑰用途(key usage)擴充欄位、用戶端到底信不信任那個根憑證,以及用戶端的時鐘:一台日期設錯的裝置,會把一張完全有效的憑證當成「尚未生效」而拒絕。

常見問題

把 CSR 貼到網頁上安全嗎?
貼到這一頁是安全的,因為沒有任何內容被傳送出去,解碼在你的瀏覽器中完成,文字不會離開你的電腦。但一般而言要小心:多數憑證解碼器由販售憑證的公司經營,其中好幾個會把你的 CSR 送到他們的伺服器。CSR 不像私鑰那樣機密,但它確實描述了你的基礎架構,你應該清楚自己用的是哪一種工具。
它能檢查憑證是否有效或受信任嗎?
不能,而且刻意不假裝可以。它只讀出這份文件所宣稱的內容,不驗證簽章、不建立到根憑證的鏈、也不連線任何 CA 或 OCSP 伺服器。瀏覽器沒有可供此用途誠實查詢的信任存放區,因此顯示綠色「受信任」標章的工具會造成誤導。這裡顯示的有效期間,是憑證中所寫的值與你自己電腦時鐘的比較結果。
我可以貼上哪些東西?
CSR、憑證,或整條憑證鏈都可以,每個 PEM 區塊會分別解碼並依序顯示,這是查看中繼憑證是否遺漏或順序錯誤最快的方式。沒有 BEGIN 與 END 行的純 base64 也能處理,因為從 JSON 欄位或 Kubernetes Secret 複製出來的憑證就是那個樣子。私鑰會被拒絕而不會被解碼。
為什麼我的 CSR 沒有顯示別名?
要嘛它真的沒有,要嘛你先前用的解碼器找不到。在 CSR 中,SAN 並不在最上層,而是放在 extensionRequest 屬性裡面,比完成的憑證多兩層。本工具會去那裡找。如果這裡也沒有顯示,代表這份 CSR 確實是在沒有 SAN 的情況下產生的,值得在送出前修正——現代瀏覽器已經完全忽略通用名稱。
該比對哪一個指紋?
除非有東西特別要求 SHA-1,否則用 SHA-256。兩個都顯示,是因為許多主控台、憑證釘選設定與廠商後台至今仍印出 SHA-1,你需要能對上眼前的那個值。兩者都是對 DER 編碼計算的,因此與 openssl x509 -fingerprint 的輸出完全一致。
為什麼日期比看起來更重要?
憑證有兩種時間編碼,2050 年之前的日期以兩位數年份儲存。RFC 5280 規定 50 到 99 代表 19xx、00 到 49 代表 20xx,因此把這個分界寫錯的解碼器,會把有效到 2049 年的憑證顯示成 1949 年就過期。本工具遵循該 RFC,並有測試固定這個行為。

最後更新:

回報問題

請提供操作步驟、預期結果及實際結果。請移除機密與個人資料。

相關工具