最近一个需求用到了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,可以成功上传,问题解决。
来源:oschina
链接:https://my.oschina.net/u/2420309/blog/740179