背景介紹
近期收到同事反饋,在C#程式中通過HTTPClient請求一個HTTPS的地址時,在本地開發環境和測試環境均能正常執行,而部署到生產環境後發生異常且穩定復現,異常提示為:【請求被中止: 未能建立 SSL/TLS 安全通道 】,而且在生產環境用瀏覽器訪問是沒問題的。
目標站點和執行環境介紹
- 目標站點SiteA(同事對接的站點):jc.ebopark.com
- 目標站點SiteB(對比站點):www.howsmyssl.com
- 生產環境伺服器MA1:Windows Server 2016 Datacenter+.NET Framework 4.8,映象來自Azure
- 測試環境伺服器T1:Windows Server 2016 Datacenter+.NET Framework 4.8,映象來自Azure
- 本地臨時VMware虛擬機器VM1:Windows Server 2016 Datacenter+.NET Framework 4.8,映象來自微軟官網
初步分析
自然的,根據異常資訊先進行一圈Google(不用百度),基本都是在說ServicePointManager.SecurityProtocol的賦值,但是本次的程式中已經配置了全部協議。在瞭解了大概背景之後,基本斷定該故障與原始碼本身的關係不大,仔細檢查原始碼後也確實沒有問題。大家也能看得出,很明顯的環境不同導致的故障,那麼宿主環境的差異就是我們優先要排查分析的線索。
這裡要引入HTTPS的一些知識點
1、關於HTTP、HTTPS、TLS的關係:HTTPS連線是由HTTP協議與TLS協議共同完成。
2、建立HTTPS連線不僅需要Client與Server雙方的TLS協議版本號相容,還需要Cipher Suites(密碼套件)相容。關於什麼是Cipher Suites可以自行查閱資料,本文不詳細展開說明。Cipher Suites的樣子如圖所示:
進一步驗證
有了以上理論支撐,下面就開始對本次案例的站點和執行環境進行一一分析;
首先,通過線上工具驗證目標站點SiteA自身的HTTPS連線功能是否OK:
截圖報告顯示SiteA支援TLS1.2、TLS1.3協議,同時也可以看到對應的密碼套件。說明該站點自身配置沒問題,這也符合同事的測試結果。
根據前面提到的知識點,下一步就需要判斷連線的Client端(即C#應用)所支援的協議和密碼套件。先看在程式中配置的是支援TLS全協議:
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 |
SecurityProtocolType.Tls |
SecurityProtocolType.Tls11 |
SecurityProtocolType.Tls12 |
(SecurityProtocolType) 12288;
其次檢視執行時部署的.NET Framework 4.8對TLS的相容情況,如下圖所示,環境對TLS1.2、TLS1.3均支援。
現在TLS協議看起來是相容的,那麼該如何檢視C#應用所使用的密碼套件?這裡用到一個工具:IISCrypto.exe
生產環境伺服器MA1的密碼套件如下圖所示。經過仔細對比,該OS沒有與目標站點SiteA匹配的密碼套件,因此無法建立連線,符合實際情況。
測試環境伺服器T1的密碼套件如下圖所示。該OS中有2組和目標站點SiteA的TLS1.2密碼套件匹配,因此可以建立連結,符合實際情況。
本地臨時VMware虛擬機器VM1的密碼套件如下圖所示,該OS中有多組和目標站點SiteA的TLS1.2密碼套件匹配,因此可以建立連結,符合實際情況。
經過上述對比後,基本可以判定是由於生產環境的伺服器密碼套件與目標站點不匹配導致。
解決方案比較簡單,使用IISCrypt工具把缺少的密碼套件勾選,並擇機重啟伺服器生效即可。
延伸1:如何建立TLS1.3協議的連線?
根據前面對幾臺伺服器的密碼套件的分析,相容的密碼套件都是最多是TLS1.2版本的,那是否真可以建立TLS1.3的連線呢?所幸我本地開發環境比較新,是Windows11,經過檢視密碼套件可以相容TLS1.3:
使用工具在只選擇TLS1.3協議的情況下,驗證是可以成功請求的:
延申2:Edge瀏覽器所支援的密碼套件自帶的,獨立於Windows。
下圖是生產環境伺服器MA1上的Edge瀏覽器的密碼套件支援情況。
通過該瀏覽器直接請求目標站點SiteA,不僅可以請求成功而且還是走的TLS1.3協議。
總結
本文針對實際開發中遇到怪異現象,結合HTTPS的理論知識,透徹的分析了故障原因並最終解決。本文中還提到了幾個實用的工具,可以更方便的檢視相關細節。最後針對生產伺服器映象預設的密碼套件問題,後續會繼續與運維同事反饋並更新。
參考資料:
- 檢視TLS線上工具:https://myssl.com/ssl.html
- IISCrypto官網:https://www.nartac.com/Products/IISCrypto/
- .NET Framework 中的傳輸層安全性 (TLS) 最佳做法:https://docs.microsoft.com/en-us/dotnet/framework/network-programming/tls
- 檢視當前連線的tls資訊-API版:https://www.howsmyssl.com/a/check
附:蘋果推送服務API的TLS資訊