有個使用 SSH.NET 連線 SFTP 交換檔案的排程,一登入便冒出錯誤 - Channel was closed 並立刻斷線,故意亂給帳號密碼則會出現 Permission denied (password),初步研判帳號密碼沒問題,錯誤另有原因。

爬文查不到明確方向,大致指向連線被伺服器切斷方面的問題,但一時無法取得伺服器端 Log 確認。中浮現幾個嫌犯:TLS 1.2、憑證、防火牆... 但訊息太模糊無從推斷。於是我有個大膽的想法,何不換個程式庫試試?或許錯誤訊息會明確一點,能再多蒐集些線索。於是我改用 WinSCP .NET Assembly and COM Library (可由 NuGet 取得),寫了一小段 PowerShell 做測試:

$sessOpt = New-Object WinSCP.SessionOptions
$sessOpt.Protocol = [WinSCP.Protocol]::Sftp
$sessOpt.HostName = $sftpHost
$sessOpt.UserName = $sftpUserId
$sessOpt.Password = $sftpPwd
# 註:嚴謹做法是預先取得伺服器憑證的指紋進行比對,以防中間人攻擊
# $sessOpt.SshHostKeyFingerprint = "ssh-rsa 2048 xxxxxxxxxxx...="
# 本測試因風險不高,選擇忽略安全檢查
$sessOpt.GiveUpSecurityAndAcceptAnySshHostKey = $true
$sess = New-Object WinSCP.Session
$sess.Open($sessOpt)
$dir = $sess.ListDirectory('.')
$dir.Files | ForEach-Object {
    if ($_.IsDirectory) {
        Write-Host "[$($_.Name)]"
    }
    else {
        Write-Host $_.Name
    }
}
$sess.Dispose()

改用 WinSCP 一樣登入就斷線,但錯誤訊息不同 - Connection has been unexpectedly closed. Server sent command exit 1.,一樣指向連線被伺服器切斷,這回用訊息爬文查到一條線索,似乎密碼過期也有此現象:

password has been expired so please go through putty or ssh and change the password and problem may be resolved.

之後連絡到伺服器管理單位證實是密碼過期造成。這次我順便新學會一個 Linux 指令 chage,可用來查詢密碼修改時間、到期時間、失效時間、帳號過期時間... 等資訊。

SFTP 元件遇到密碼過期沒提供明確訊息,是繞一大圈才找出問題的幫兇。為了釐清責任歸屬,找了 CentOS VM 將帳號設為密碼過期,實測 SSH 或 SFTP 登入,都有明確的 Your account has expired 提示:

因此推論,是 SFTP 程式庫錯誤訊息轉達不精確。若能取得號密碼(實務上未必辦得到),用 ssh 客戶端程式測試是最快釐清問題的方法,若不行,依本次經驗可優先檢查密碼是否過期。

A case of Linux closing the connection immediately after .NET client login.


Comments

Be the first to post a comment

Post a comment