Java中使用OPENSSH IdentityFile连接SFTP失败的问题排查
解决JSch兼容OpenSSH密钥及RSA认证失败问题
问题背景
开发Java SFTP应用,需兼容两种认证方式:测试环境用密码认证,生产环境用标准id_rsa OpenSSH密钥认证。目前密码连接正常,但密钥连接出现两类错误:
- 使用OpenSSH格式私钥时,
jsch.addIdentity(identityFile)报错invalid privatekey: [B@48c76607 - 使用RSA格式私钥时,
jschSession.connect()报错com.jcraft.jsch.SftpException: Auth fail
当前实现代码:
JSch jsch = new JSch(); jsch.setKnownHosts(knownHosts); if (!identityFile.equals("")) { jsch.addIdentity(identityFile, passphrase); } Session jschSession = jsch.getSession(user, host, port); jschSession.setConfig("StrictHostKeyChecking", "no"); if (identityFile.equals("")) { jschSession.setPassword(pass); jschSession.setConfig("PreferredAuthentications", "password"); } else { jschSession.setConfig("PreferredAuthentications", "publickey"); } jschSession.connect(); ChannelSftp channelSftp = (ChannelSftp) jschSession.openChannel("sftp"); channelSftp.connect();
环境信息:
- JSch版本:
jsch-0.1.55.jar - Java版本:Java 8
- 服务器:OpenSSH_8.9p1 Ubuntu-3ubuntu0.3
- 密钥权限配置正确,Shell/FileZilla用密钥连接正常,但Java无法连接
RSA密钥连接时JSch日志:
Connecting to <HOST> port <PORT> Connection established Remote version string: SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.3 Local version string: SSH-2.0-JSCH-0.1.54 CheckCiphers: aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,3des-ctr,arcfour,arcfour128,arcfour256 CheckKexes: diffie-hellman-group14-sha1,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521 CheckSignatures: ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521 SSH_MSG_KEXINIT sent SSH_MSG_KEXINIT received kex: server: curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,sntrup761x25519-sha512@openssh.com,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256 kex: server: rsa-sha2-512,rsa-sha2-256,ecdsa-sha2-nistp256,ssh-ed25519 kex: server: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com kex: server: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com kex: server: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1 kex: server: umac-64-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,umac-128@openssh.com,hmac-sha2-256,hmac-sha2-512,hmac-sha1 kex: server: none,zlib@openssh.com kex: server: none,zlib@openssh.com kex: server: kex: server: kex: client: ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group1-sha1 kex: client: ssh-rsa,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521 kex: client: aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-ctr,aes192-cbc,aes256-ctr,aes256-cbc kex: client: aes128-ctr,aes128-cbc,3des-ctr,3des-cbc,blowfish-cbc,aes192-ctr,aes192-cbc,aes256-ctr,aes256-cbc kex: client: hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96 kex: client: hmac-md5,hmac-sha1,hmac-sha2-256,hmac-sha1-96,hmac-md5-96 kex: client: none kex: client: none kex: client: kex: client: kex: server->client aes128-ctr hmac-sha1 none kex: client->server aes128-ctr hmac-sha1 none SSH_MSG_KEX_ECDH_INIT sent expecting SSH_MSG_KEX_ECDH_REPLY Host '<HOST>' is known and matches the ECDSA host key SSH_MSG_NEWKEYS sent SSH_MSG_NEWKEYS received SSH_MSG_SERVICE_REQUEST sent SSH_MSG_SERVICE_ACCEPT received Authentications that can continue: publickey Next authentication method: publickey Disconnecting from <HOST> port <PORT>
解决方案
1. 处理OpenSSH密钥格式不兼容问题
JSch 0.1.55不支持开头为-----BEGIN OPENSSH PRIVATE KEY-----的密钥格式,需将其转换为传统RSA格式:
ssh-keygen -p -f id_rsa -m pem -P "" -N ""
参数说明:
-p:修改私钥密码-f id_rsa:指定目标私钥文件-m pem:转换为PEM格式(传统RSA格式)-P "":原密码为空(若有密码替换为实际值)-N "":新密码为空(若需设置密码替换为实际值)
转换后私钥开头为-----BEGIN RSA PRIVATE KEY-----,即可被JSch识别。
2. 修复RSA密钥认证失败问题
从日志可见,服务器支持的签名算法为rsa-sha2-512,rsa-sha2-256,但JSch默认未启用这些算法,需手动添加配置:
修改代码中密钥认证分支的配置:
if (!identityFile.isEmpty()) { jsch.addIdentity(identityFile, passphrase); // 启用RSA SHA2系列签名算法 jschSession.setConfig("PubkeyAcceptedKeyTypes", "+ssh-rsa,rsa-sha2-256,rsa-sha2-512"); jschSession.setConfig("PreferredAuthentications", "publickey"); }
注意:确保使用JSch 0.1.55版本(该版本首次支持rsa-sha2算法,0.1.54及以下版本不支持)。
3. 优化代码逻辑
简化重复的identityFile判断逻辑:
JSch jsch = new JSch(); jsch.setKnownHosts(knownHosts); Session jschSession = jsch.getSession(user, host, port); jschSession.setConfig("StrictHostKeyChecking", "no"); if (!identityFile.isEmpty()) { jsch.addIdentity(identityFile, passphrase); jschSession.setConfig("PubkeyAcceptedKeyTypes", "+ssh-rsa,rsa-sha2-256,rsa-sha2-512"); jschSession.setConfig("PreferredAuthentications", "publickey"); } else { jschSession.setPassword(pass); jschSession.setConfig("PreferredAuthentications", "password"); } jschSession.connect(); ChannelSftp channelSftp = (ChannelSftp) jschSession.openChannel("sftp"); channelSftp.connect();
4. 额外检查项
- 确认服务器
sshd_config中已开启PubkeyAuthentication yes - 确认用户家目录下的
.ssh/authorized_keys文件权限为600,.ssh目录权限为700 - 确认
authorized_keys中已添加对应私钥的公钥内容
内容的提问来源于stack exchange,提问作者Marco Frag Delle Monache
相关产品推荐
相关产品推荐

