最近一個需求用到了SFTP上傳功能,同事之前已經封裝好了SFTP工具類,用的是JSch,本着不要重復造輪子的想法,就直接拿來用了。交代下環境,JDK為1.7,JSch版本為0.1.51。自測通過、測試環境也OK,但上到生產環境卻拋出Algorithm negotiation fail異常,當即傻眼,下面是具體的異常信息:
com.jcraft.jsch.JSchException: Algorithm negotiation fail
at com.jcraft.jsch.Session.receive_kexinit(Session.java:583) ~[jsch-0.1.51.jar:na]
at com.jcraft.jsch.Session.connect(Session.java:320) ~[jsch-0.1.51.jar:na]
更納悶的是,在本端(Client端)下用Linux命令SFTP(參考linux下FTP、SFTP命令詳解)連接對端(Server端)是成功的,也能上傳,首先排除了用戶名/密碼錯誤、網絡不通、未添加白名單之類的原因了。然后想到是程序本身的問題,但為什么開發環境、測試環境都沒拋錯呢?難道是環境問題嗎?用ssh -V命令查看ssh版本,測試環境的本端和對端,以及生產環境的本端均是“OpenSSH_5.3p1, OpenSSL 1.0.0-fips 29 Mar 2010”,但是生產環境的對端卻是“OpenSSH_6.7p1, OpenSSL 1.0.1e-fips 11 Feb 2013”。看來真是環境問題了。
冷靜下來,回到這個異常Algorithm negotiation fail,其意思是算法協商失敗。查看jsch源碼,異常發生在connect階段。上網查找資料(SSH協議介紹),發現SSH通訊過程的五個階段中,有一個是密鑰和算法協商階段,在這個階段, 雙方根據本端和對端支持的算法,協商出最終使用的算法。問題就應該出在了這里。5.3和6.7不同版本的OpenSSH默認的算法列表不同,導致了算法協商失敗。參考com.jcraft.jsch.JSchException: Algorithm negotiation fail
那么如何才能知道不同版本OpenSSH默認的算法列表呢?參考What's openssh default kexalgorithms?通過ssh -vvv serverIp命令,如如下圖所示:
其中1和2標記的分別是5.3和6.7版本OpenSSH默認的KexAlgorithms,可以看到,(本端)OpenSSH 5.3支持的diffie-hellman-group1-sha1
和 diffie-hellman-group-exchange-sha1 算法已經不在(對端)
OpenSSH 6.7的默認列表里面。
原來,ssh升級后,為了安全,默認不再采用原來一些加密算法。既然沒有了原來的一些加密算法,那么就手工添加進去,參照這篇博文。編輯
/etc/sshd_config,加上 KexAlgorithms diffie-hellman-group1-sha1,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha1
重啟服務
sshd。
就在以為能搞定的時候,對端的同事(因為是我連接他們的SFTP服務器,因此上述添加修改工作是由他們來做的)說修改后重啟服務報錯了:
因為服務器不在我這邊,我不能親自調試,這下我也沒轍了。
最后,不甘心每天要手動上傳,去JSch官網看一下,竟然有所收獲,在它的ChangeLog里發現,
Changes since version 0.1.52: - bugfix: the rekey initiated by the remote may crash the session.
是說修復了“由遠程發起的密鑰更新可能會使會話崩潰”的bug,這說的就是我遇到的問題啊,把JSch的版本升級到了最新的0.1.53,可以成功上傳,問題解決。
轉載於:https://my.oschina.net/greatqing/blog/740179