牛年最後一枚茶包。(希望啦)

某個重要又緊急的案件,ASP.NET 網站對外呼叫 WebAPI 功能出現錯誤,因網路環境設定有狀況,連瀏覽器測試都時好時壞,導致無法確定是網路不通還是程式出錯。經過一番努力,狀況進展到瀏覽器檢視 HTTPS 網址 OK、PowerShell Test-NetworkConenction (參考:Windows 測試 TCP 連線,比 Telnet 更好的方法) 測試 443 Port 有通,但 Invoke-WebRequest (參考:野外求生系列 - 無工具 WebApi 徒手測試) 出錯,訊息為「基礎連接已關閉: 接收時發生未預期的錯誤」。

由於不確定網路問題是否完全排除,我鬼打牆好一陣子,還換了 System.Net.WebClient 測試一樣不通且錯誤訊息相同。最後,我在 PowerShell 加了 try catch 印出詳細錯誤訊息才撥雲見日:

$wc = New-Object System.Net.WebClient
try { 
    $wc.DownloadString('https://blah.bubu.blahbu')
} 
catch {
    $wc.Excetion.ToString()
}

詳細錯誤訊息為:

System.Management.Automation.MethodInvocationExcption: 
以 "1" 引數呼叫 "DownloadString" 時發生例外狀況: "基礎連接已關閉: 接收時發生未預期的錯誤" 
--> System.Net.WebExcetion: "基礎連接已關閉: 接收時發生未預期的錯誤" 
--> System.ComponentModel.Win32Execption: "客戶端與伺服器無法溝通,因為它們沒有公用的演算法"
  於 System.Net.SSPIWrapper.AcquireCredentialHandle(SSPIInterface SecModule, String package ...

看到詳細訊息我瞬間就明白了,這不就不折不扣是他 X 的 TLS 1.2 問題?都解過多少次了,但這回摻進「網路可能不通」的因素,一時沒有意會到。對照之前的經驗,TLS/SSL 問題錯誤訊息具有多種樣態:

  1. 基礎連接已關閉: 傳送時發生未預期的錯誤 / 驗證失敗,因為遠端群體已經關閉傳輸資料流 | Authentication failed because the remote party has closed the transport stream。案例 案例
  2. 基礎連接已關閉: 無法為 SSL/TLS 安全通道建立信任關係 | Could not establish trust relationship for SSL/TLS secure channel。案例
  3. 基礎連接已關閉: 無法讀取來自傳輸連線的資料: 遠端主機已強制關閉現有的連線 | Unable to read data from the transport connection: An existing connection was forceibly closed by the remote host. 案例
  4. 基礎連接已關閉: 接收時發生未預期的錯誤 / 客戶端與伺服器無法溝通,因為它們沒有公用的演算法 | The client and server cannot communicate, because they do not possess a common algorithm (本次案例)

但共同特徵是:443 Port 測試 OK、連線時很快得到回應、訊息有「基礎連接已關閉 / The underlying connection was closed」字樣,遇此狀況可排除網路不通因素,朝 SSL 憑證無效或 TLS 協定支援方向著手。

PowerShell 4.0/5.1 的 .NET 版本是 4.5 參考、問題 ASP.NET 網站是 4.5.2,依 Windows 停用 TLS 1.0 之配套作業整理,NET 4.5 內建 TLS 1.2 支援,但需透過 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 設成預設協定,4.6+ 才預設 TLS 1.2。目前大部分的網站也都已停用 TLS 1.x,PowerShell 或 .NET 4.5 遇到此類狀況的機率將會愈來愈高。

最後,參考 .NET 3.5 TLS 1.2 踩雷記設定 SystemDefaultTlsVersions、SchUseStrongCrypto Registry 並重啟 AppPool 後,問題排除。

重要心得:

  1. 若 Test-NetConnection -Port 443 及瀏覽器測試 OK,但 PowerShell Invoke-WebRequest 或 .NET 程式很快傳回帶有「基礎連接已關閉 / The underlying connection was closed」之錯誤訊息,十之八九是 TLS 憑證或協定問題,不要懷疑網站不通。網路不通的症狀是等一陣子,再出現「無法連接至遠端伺服器」訊息。
  2. 當 PowerShell 錯誤訊息不夠清楚,用 try catch 列出 $_.Exception.ToString() 查看詳細資訊

Summary of my experience of C#/PowerShell 'The underlying connection was closed' errors, inspect TLS protocol or certificate issue first.


Comments

Be the first to post a comment

Post a comment