概念
SSH是一个协议标准,OpenSSH是它的开源实现,包含有客户端与服务端。目前SSH有两大版本,分别为SSH1和SSH2。SSH的登录过程分为5个阶段,这个过程中使用了密钥交换算法、非对称加解密、对称加解密、认证、消费验证等等技术,使SSH的运行目前来说安全性很高。
最近因为在为公司的Web项目集成sftp客户端,但因为项目是一个非常老旧的项目,运行在win2003/JDK1.5下面,这就导致了Jsch库无法使用最新版本,而旧的jdk1.5其中的JCE库,又只支持少量的加密算法,那么旧的Jcsh库就一直无法与Sftp服务连接(新建的Sftp服务使用的SSH比较新)。当然,这个问题最终还是解决了,只是费了不少力气,解决过程中也重点研究了SSH的连接过程,本文就记录一下。
连接过程
SSH的连接登陆过程有5个阶段,分别1.版本号协商阶段 2.密钥和算法协商阶段 3.认证阶段 4.会话请求阶段 5.会话交互阶段
其中密钥与算法协商阶段
、认证阶段
是整个登陆连接过程的关键,也是安全性的保证。
版本号协商阶段
客户端向服务端发起TCP连接,连接建立后,服务端向客户端发送第一个报文,包括版本标志字符串,格式为”SSH-协议版本号.次协议版本号-软件版本号“。
debug1: Local version string SSH-2.0-OpenSSH_7.4
客户端收到报文后,解析协议版本号,如果服务端的协议版本号比自己的低,且客户端能支持服务端的低版本,就使用服务端的协议号,否则使用自己的协议版本号。
debug1: Remote protocol version 2.0, remote software version OpenSSH_5.3
客户端回复服务端一个报文,包含了客户端决定使用的协议版本号。
debug1: match: OpenSSH_5.3 pat OpenSSH_5* compat 0x0c000000
服务端比较客户端发过来的版本号,决定是否能同客户端交互。 如果协商成功,就进入密钥和算法协商阶段。否则服务端断开TCP连接。
密钥和算法协商阶段
这个阶段叫KEXINIT
,由客户端发出SSH2_MSG_KEXINIT
消息开始,然后是SSH2_MSG_KEX_ECDH
开始协商确定密钥算法,过程使用,由SSH2_MSG_NEWKEYS
确认最终确定的共享密钥。
服务端和客户端分别发送算法协商报文给对方,报文中包含自己支持的公钥算法列表、加密算法列表、消息验证码(MAC,Message Authentication Code)算法列表、压缩算法列表等。服务端和客户端根据对方和自己支持的算法得出最终使用的算法。服务端和客户端利用DH(diffie-hellman)交换算法、主机密钥对等参数,生成会话密钥和会话ID。会话密钥用于在后续的通信过程中两端对传输的数据进行加密和解密,而会话ID用于认证过程。
- 服务端将服务端公钥发送给客户端。
- 服务端生成会话ID ,设为 id ,发送给客户端。
- 客户端生成会话密钥,设为 key ,并计算 res = id 异或 key。
- 客户端将 res 用服务端公钥进行加密,将结果发送给服务端。
- 服务端用服务端私钥进行解密,得到 res。
- 服务器计算 res 异或 id,得到 key。 至此服务端和客户端都知道了会话密钥和会话ID,以后的数据传输都使用会话密钥进行加密和解密。
认证阶段
认证开始后会有一个设定好的顺序例如publickey,gssapi-keyex,gssapi-with-mic,password 首先用publickey的方式即秘钥认证,如果秘钥认证通过的话将不进行使用密码的口令认证,如果秘钥认证失败则使用口令认证。 我们如果想要免去用户名密码登陆可以使用秘钥认证的方式。
基于公钥和私钥的验证方式
- 首先使用ssh-keygen程序生成公钥 id_dsa.pub 和私钥 id_dsa,一般是在客户端上生成,然后把 id_dsa.pub 通过某种方式发送给服务端。 服务端放在将要远程登录过来的那个账号的目录的.ssh目录下面。
- 客户端使用密钥和算法协商阶段生成的会话密钥加密账号、认证方法、id_dsa.pub,将结果发送给服务端。
- 服务端使用会话密钥解密报文,得到账号、id_dsa.pub。 服务端在这个账号的目录的.ssh目录下找对应的公钥,如果没有找到,发送失败消息给客户端,如果找到,比较客户发送过来的这个公钥和找到的公钥,如果内容相同,服务端生成一个随机的字符串,简称“质询”,然后使用找到的公钥加密这个质询,然后使用会话密钥再次加密。
- 服务端把这个双重加密的数据发送给客户端。
- 客户端使用会话密钥解密报文,然后使用id_dsa再次解密数据,得到质询。
- 客户端使用会话密钥加密质询,发送给服务端。
- 服务端使用会话密钥解密报文,得到质询,判断是不是自己生成的那个质询,如果不相同,发送失败消息给客户端,如果相同,认证通过。4.1.2. 基于账号和口令的验证方式:
- 客户端使用密钥和算法协商阶段生成的会话密钥加密账号、认证方法、口令,将结果发送给服务器。
- 服务端使用获得的会话密钥解密报文,得到账号和口令。
- 服务端对这个账号和口令进行判断,如果失败,向客户端发送认证失败报文,其中包含了可以再次认证的方法列表。
- 客户端从认证方法列表中选择一种方法进行再次认证。 这个过程反复进行,直到认证成功或者认证次数达到上限,服务端关闭本次TCP连接。
基于账号和口令的验证方式
- 客户端使用密钥和算法协商阶段生成的会话密钥加密账号、认证方法、口令,将结果发送给服务器。
- 服务端使用获得的会话密钥解密报文,得到账号和口令。
- 服务端对这个账号和口令进行判断,如果失败,向客户端发送认证失败报文,其中包含了可以再次认证的方法列表。
- 客户端从认证方法列表中选择一种方法进行再次认证。 这个过程反复进行,直到认证成功或者认证次数达到上限,服务端关闭本次TCP连接。
本次集成难题解决
Jsch版本不支持JDK1.5
降级版本到0.1.52
Jsch自带的密钥协商算法不受支持
在2023年,大多数服务器所安装的OpenSSH高于8.8
这是因为低版本的Jsch所支持的算法太少的原因,而且因为JDK1.5导致无法升级Jsch库,那么解决思路有两个
1、服务器的SSH服务新增低版本Jcsh所支持的算法,而且这些算法经常都是被证实不安全、有漏洞的算法,不过可以使用于纯内网环境。
2、为Jsch新增更好的算法
操作
查询算法支持
查看linux服务器上支持的(所有的)ssh对称秘钥:
ssh -Q cipher
查看支持身份验证加密(启用的)的对称秘钥:
ssh -Q cipher-auth
查看支持的消息完整性秘钥:
ssh -Q mac
修改配置支持算法
#结尾添加下面的内容,用来指定加密协议:
Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc,,aes192-cbc,aes256-cbc,aes128-gcm@openssh.com,rijndael-cbc@lysator.liu.se,aes256-gcm@openssh.com,chacha20-poly1305@openssh.com
Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,arcfour
Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc,aes128-gcm@openssh.com,rijndael-cbc@lysator.liu.se,aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,hmac-sha1,hmac-sha1-96,hmac-sha2-256,hmac-sha2-512,hmac-md5,hmac-md5-96,umac-64@openssh.com,umac-128@openssh.com,hmac-sha1-etm@openssh.com,hmac-sha1-96-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-md5-etm@openssh.com,hmac-md5-96-etm@openssh.com,umac-64-etm@openssh.com,umac-128-etm@openssh.com
OpenSSH版本过低漏洞
登陆连接过程
以一段ssh连接日志结束本文
> ssh -vvv devis@10.3.2.183
版本交换协商阶段开始
OpenSSH_for_Windows_8.1p1, LibreSSL 3.0.2
debug1: Reading configuration data C:\\Users\\winuser/.ssh/config
debug1: C:\\Users\\winuser/.ssh/config line 2: Applying options for *
debug3: Failed to open file:C:/ProgramData/ssh/ssh_config error:2
debug2: resolve_canonicalize: hostname 10.3.2.183 is address
debug2: ssh_connect_direct
debug1: Connecting to 10.3.2.183 [10.3.2.183] port 22.
debug1: Connection established.
debug1: identity file C:\\Users\\winuser/.ssh/devis_213_rsa type 0
debug3: Failed to open file:C:/Users/winuser/.ssh/devis_213_rsa-cert error:2
debug3: Failed to open file:C:/Users/winuser/.ssh/devis_213_rsa-cert.pub error:2
debug1: identity file C:\\Users\\winuser/.ssh/devis_213_rsa-cert type -1
debug1: Local version string SSH-2.0-OpenSSH_for_Windows_8.1
debug1: Remote protocol version 2.0, remote software version OpenSSH_8.4p1 Debian-5
debug1: match: OpenSSH_8.4p1 Debian-5 pat OpenSSH* compat 0x04000000
debug2: fd 3 setting O_NONBLOCK
debug1: Authenticating to 10.3.2.183:22 as 'devis'
debug3: hostkeys_foreach: reading file "C:\\Users\\winuser/.ssh/known_hosts"
debug3: record_hostkey: found key type ECDSA in file C:\\Users\\winuser/.ssh/known_hosts:17
debug3: load_hostkeys: loaded 1 keys from 10.3.2.183
debug3: Failed to open file:C:/Users/winuser/.ssh/known_hosts2 error:2
debug3: Failed to open file:C:/ProgramData/ssh/ssh_known_hosts error:2
debug3: Failed to open file:C:/ProgramData/ssh/ssh_known_hosts2 error:2
debug3: order_hostkeyalgs: prefer hostkeyalgs: ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521
密钥交换、算法协商阶段开始
debug3: send packet: type 20
debug1: SSH2_MSG_KEXINIT sent
debug3: receive packet: type 20
debug1: SSH2_MSG_KEXINIT received
debug2: local client KEXINIT proposal
debug2: KEX algorithms: curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256,diffie-hellman-group14-sha1,ext-info-c
debug2: host key algorithms: ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa
debug2: ciphers ctos: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
debug2: ciphers stoc: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
debug2: MACs ctos: 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
debug2: MACs stoc: 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
debug2: compression ctos: none,zlib@openssh.com,zlib
debug2: compression stoc: none,zlib@openssh.com,zlib
debug2: languages ctos:
debug2: languages stoc:
debug2: first_kex_follows 0
debug2: reserved 0
debug2: peer server KEXINIT proposal
debug2: KEX algorithms: curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256
debug2: host key algorithms: rsa-sha2-512,rsa-sha2-256,ssh-rsa,ecdsa-sha2-nistp256,ssh-ed25519
debug2: ciphers ctos: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
debug2: ciphers stoc: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,aes256-gcm@openssh.com
debug2: MACs ctos: 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
debug2: MACs stoc: 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
debug2: compression ctos: none,zlib@openssh.com
debug2: compression stoc: none,zlib@openssh.com
debug2: languages ctos:
debug2: languages stoc:
debug2: first_kex_follows 0
debug2: reserved 0
密钥与算法确认
debug1: kex: algorithm: curve25519-sha256
debug1: kex: host key algorithm: ecdsa-sha2-nistp256
debug1: kex: server->client cipher: chacha20-poly1305@openssh.com MAC: <implicit> compression: none
debug1: kex: client->server cipher: chacha20-poly1305@openssh.com MAC: <implicit> compression: none
debug3: send packet: type 30
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug3: receive packet: type 31
debug1: Server host key: ecdsa-sha2-nistp256 SHA256:tqXzJB2BoSjJQKSCUa8sk3WpL0qbIR9dtaDYcbhylc0
debug3: hostkeys_foreach: reading file "C:\\Users\\winuser/.ssh/known_hosts"
debug3: record_hostkey: found key type ECDSA in file C:\\Users\\winuser/.ssh/known_hosts:17
debug3: load_hostkeys: loaded 1 keys from 10.3.2.183
debug3: Failed to open file:C:/Users/winuser/.ssh/known_hosts2 error:2
debug3: Failed to open file:C:/ProgramData/ssh/ssh_known_hosts error:2
debug3: Failed to open file:C:/ProgramData/ssh/ssh_known_hosts2 error:2
debug1: Host '10.3.2.183' is known and matches the ECDSA host key.
debug1: Found key in C:\\Users\\winuser/.ssh/known_hosts:17
debug3: send packet: type 21
debug2: set_newkeys: mode 1
debug1: rekey out after 134217728 blocks
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug3: receive packet: type 21
debug1: SSH2_MSG_NEWKEYS received
debug2: set_newkeys: mode 0
debug1: rekey in after 134217728 blocks
debug3: unable to connect to pipe \\\\.\\pipe\\openssh-ssh-agent, error: 2
debug1: pubkey_prepare: ssh_get_authentication_socket: No such file or directory
debug1: Will attempt key: C:\\Users\\winuser/.ssh/devis_213_rsa RSA SHA256:JEWGEwVxg+D2i3Ieu4CM+dmy27+aXM0M6b/ilMpLHKQ explicit
debug2: pubkey_prepare: done
debug3: send packet: type 5
debug3: receive packet: type 7
debug1: SSH2_MSG_EXT_INFO received
debug1: kex_input_ext_info: server-sig-algs=<ssh-ed25519,sk-ssh-ed25519@openssh.com,ssh-rsa,rsa-sha2-256,rsa-sha2-512,ssh-dss,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,sk-ecdsa-sha2-nistp256@openssh.com,webauthn-sk-ecdsa-sha2-nistp256@openssh.com>
认证阶段开始
debug3: receive packet: type 6
debug2: service_accept: ssh-userauth
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug3: send packet: type 50
debug3: receive packet: type 51
debug1: Authentications that can continue: publickey,password 公钥,密码两种认证方法,先从公钥开始,如失败,再尝试密码
debug3: start over, passed a different list publickey,password
debug3: preferred publickey,keyboard-interactive,password
debug3: authmethod_lookup publickey
debug3: remaining preferred: keyboard-interactive,password
debug3: authmethod_is_enabled publickey
debug1: Next authentication method: publickey
debug1: Offering public key: C:\\Users\\winuser/.ssh/devis_213_rsa RSA SHA256:JEWGEwVxg+D2i3Ieu4CM+dmy27+aXM0M6b/ilMpLHKQ explicit
debug3: send packet: type 50
debug2: we sent a publickey packet, wait for reply
debug3: receive packet: type 60
debug1: Server accepts key: C:\\Users\\winuser/.ssh/devis_213_rsa RSA SHA256:JEWGEwVxg+D2i3Ieu4CM+dmy27+aXM0M6b/ilMpLHKQ explicit
debug3: sign_and_send_pubkey: RSA SHA256:JEWGEwVxg+D2i3Ieu4CM+dmy27+aXM0M6b/ilMpLHKQ
debug3: sign_and_send_pubkey: signing using rsa-sha2-512
debug3: send packet: type 50
debug3: receive packet: type 52
debug1: Authentication succeeded (publickey).
Authenticated to 10.3.2.183 ([10.3.2.183]:22).
认证成功之后,交互会话开始
debug1: channel 0: new [client-session]
debug3: ssh_session2_open: channel_new: 0
debug2: channel 0: send open
debug3: send packet: type 90
debug1: Requesting no-more-sessions@openssh.com
debug3: send packet: type 80
debug1: Entering interactive session.
debug1: pledge: network
debug1: ENABLE_VIRTUAL_TERMINAL_INPUT is supported. Reading the VTSequence from console
debug3: This windows OS supports conpty
debug1: ENABLE_VIRTUAL_TERMINAL_PROCESSING is supported. Console supports the ansi parsing
debug3: Successfully set console output code page from:65001 to 65001
debug3: Successfully set console input code page from:936 to 65001
debug3: receive packet: type 80
debug1: client_input_global_request: rtype hostkeys-00@openssh.com want_reply 0
debug3: receive packet: type 4
debug1: Remote: /home/devis/.ssh/authorized_keys:1: key options: agent-forwarding port-forwarding pty user-rc x11-forwarding
debug3: receive packet: type 4
debug1: Remote: /home/devis/.ssh/authorized_keys:1: key options: agent-forwarding port-forwarding pty user-rc x11-forwarding
debug3: receive packet: type 91
debug2: channel_input_open_confirmation: channel 0: callback start
debug2: fd 3 setting TCP_NODELAY
debug2: client_session2_setup: id 0
debug2: channel 0: request pty-req confirm 1
debug3: send packet: type 98
debug2: channel 0: request shell confirm 1
debug3: send packet: type 98
debug2: channel_input_open_confirmation: channel 0: callback done
debug2: channel 0: open confirm rwindow 0 rmax 32768
debug3: receive packet: type 99
debug2: channel_input_status_confirm: type 99 id 0
debug2: PTY allocation request accepted on channel 0
debug2: channel 0: rcvd adjust 2097152
debug3: receive packet: type 99
debug2: channel_input_status_confirm: type 99 id 0
debug2: shell request accepted on channel 0
debug2: client_check_window_change: changed
debug2: channel 0: request window-change confirm 0
debug3: send packet: type 98
# devis @ 2.183 in ~$