Java 实现 SSH 协议的客户端登录认证方式--转载

<h2 id="major1">背景

在开篇之前,让我们先对 SSH 协议有个宏观的大致了解,这样更有利于我们对本文的加深了解。首先要提到的就是计算机网络协议,所谓计算机网络协议,简单的说就是定义了一套标准和规则,使得不同计算机之间能够进行正常的网络通信,不至于出现在一台机器上发出的指令到另一台机器上成了不可认的乱码,SSH 就是众多协议的其中之一。经典的七层 OSI 模型(Open System Interconnection Reference Model)出现后,大大地解决了网络互联的兼容性问题,它将网络划分成服务、接口和协议三个部分,而协议就是说明本层的服务是如何实现的。SSH、Telnet 协议则主要被使用在用户层中(如图 1 深色部分所示),即应用层、表现层和会话层。

图 1. 七层 OSI 模型

SSH(Secure Shell Protocol)是在一个不安全的网络,进行安全远程登录和其他安全网络服务的协议。这个定义出自于 IETF(Internet Engineering Task Force)。在 TCP/IP 五层模型中,SSH 是被应用于应用层和传输层的安全协议。

传统的网络传输,如:Telnet、FTP 等,采用的是明文传输数据和口令,这样很容易被黑客这样的中间人嗅探到传输过程中的数据,大大降低了网络的通信安全。而 SSH 协议则采用数据加密的方式建立起一个安全的网络传输信道,增强了数据在网络传输过程中的安全性。数据加密程度的复杂,会导致占用更多的网络资源。SSH 会对加密数据进行一定的压缩操作,从而减缓对网络带宽的占用。总结起来,SSH 的优点如下:

    数据加密,提高安全性
    数据压缩,提高网络的传输速度。

在对 SSH 有了一个初步的认识之后,我们来看看 SSH 协议是如何做到数据的安全通信。首先来看下 SSH 协议的主要架构:

图 2. SSH 协议的构成

传输层协议: 通常运行在 TCP/IP 的上层,是许多安全网络服务的基础,提供了数据加密、压缩、服务器认证以及保证数据的完整性。比如,公共密钥算法、对称加密算法、消息验证算法等。

用户认证协议:运行在 SSH 协议的传输层之上,用来检测客户端的验证方式是否合法。

连接协议:运行在用户认证层之上,提供了交互登录会话、远程命令的执行、转发 TCP/IP 连接等功能,给数据通讯提供一个安全的,可靠的加密传输信道。

在实际的工作中,很多目标机器往往是我们无法直接操作的,这些机器可能是一个公司机房的服务器,也可能是一个远在大洋彼岸的客户环境。这时候我们必须要远程登录到目标机器,执行我们需要的操作,这样不仅降低了运营成本,也提高了执行效率。我们常见的远程登录协议有 SSH、Telnet 等。如上文所提到,Telnet 使用的是明文传输,这样对别有用心的“中间人”来说就有了可乘之机,相对 Telnet 协议,SSH 协议的安全性就高了很多。这样的特性,也使得 SSH 协议迅速被推广,很多的大型项目中都或多或少的使用到了这个协议。下面本文主要讨论 SSH 协议中用户认证协议层,并且下文中统一将远程机器称为服务器(Server),本地机器称为客户端 (Client)。

常见的 SSH 协议认证方式有如下几种:

    基于口令的验证方式(password authentication method),通过输入用户名和密码的方式进行远程机器的登录验证。
  • 基于公共密钥的安全验证方式(public key authentication method),通过生成一组密钥(public key/private key)来实现用户的登录验证。
  • 基于键盘交互的验证方式(keyboard interactive authentication method),通过服务器向客户端发送提示信息,然后由客户端根据相应的信息通过手工输入的方式发还给服务器端。

SSH 的主要工作流程:

图 3. SSH 登录工作流程

通过这个张流程图,我们可以看出,在用户对远程机器访问的时候,首先,是得到了服务器端的一个连接句柄,这里可以理解为是一个 session,然后客户端可以通过这个句柄取得一些服务器的基本信息,如 SSH 的版本,服务器的版本信息以及一些加密的算法信息等。其次,客户端可以对这些信息作分析,来匹配当前的客户端的加密算法、验证方式是否符合服务器的配置,然后取得彼此可接受的方式,这里可以认为是双方的协商。最后,当双方达成一致后,一个安全的信道也就真正建立起来了,此时用户就可以对远程机器做想要的操作了。当我们对此有了一定的了解后,就可以初步判断,在平时工作中,我们通过 SSH 协议去连接一个远程机器报错的时候,问题出现在哪个流程上。下面通过具体的 Java 例子来讲解用户验证方式的原理。

在开始前,我们要做一些环境的准备工作。

    一台本地机器,操作系统是 Windows 用来作为客户端
  • 一台远程机器,操作系统是 Linux 用来作为服务器端
  • OpenSSH 工具
  • Putty 工具

首先,要确保服务器端上已经安装了 OpenSSH 工具,并且 SSH 的服务已经启动,可以通过如下命令来进行查看:

查看是否已经安装了 OpenSSH

查看 SSH 服务是否启动。

Checking for service sshd running 在 Windows 机器,即客户端上尝试使用 Putty 工具连接远程机器。

图 4. SSH 连接成功

到目前为止,我们已经可以正常的连接到这台远程机器。下面我们就要通过 Java 代码的方式来实现我们自己的这个远程登录的操作。

在 SSH 协议中定义了一些消息代码,而 50 至 79 这些代码是保留给用户认证协议层使用的,而 80 以上的数字是用于协议运行的,所以如果在用户认证协议验证之前,如果我们得到的消息代码是这个范围的,SSH 会返回错误信息,并断开连接。例如如以下几种消息所对应的代码号:

SSH_MSG_USERAUTH_REQUEST 50:用户发送一个验证请求。

SSH_MSG_USERAUTH_FAILURE 51:用户验证请求失败。

SSH_MSG_USERAUTH_SUCCESS 52:用户验证请求成功。

那么对于不同的认证方式,又有其各自的消息代码。

在每次客户端发送请求的时候,服务器都会检查当前的 service name 和 username 是否合法,如果当前的 service name 或者 username 不可用,那么服务器端会立刻断掉请求连接。

下面来实现一个对 service name 验证的请求,发送数据格式如下:

byte SSH_MSG_SERVICE_REQUEST

string service name in US-ASCIII

具体代码如下:

转换后发送的消息如下:

[5,12,115,104,45,117,101,114,97,116,104]

然后再对此进行算法加密,发送到服务器端。

当前协议使用的 service name 是”ssh-userauth”,如果客户端请求的不是这个 service name,那么服务器会报如下错误:

如果客户端通过了 service name 的验证后,下一步我们就可以实现具体的认证方式了。流程图如下所示:

图 5. Authentication 类图

TransportManager 类是用来处理传输协议层的业务逻辑。在这里主要处理数据的解密、加密、压缩等操作,这些功能的具体实现主要通过 TransportControl 类来完成,TrasportControl 类会根据客户端和服务器端协商的数据算法来选择具体的算法如 sha-1、MD5 等。通过 TransportControl 类处理完的数据会存储到 Packets 类里,生成一个数据包的列表,为 AuthManager 类提供必要的数据信息。Connect 类是用来处理连接协议层的业务逻辑。主要用于得到一个远程机器的连接句柄、产生一个安全信道、对 TransportManager 类做数据初始化操作等。AuthManager 类是用来处理认证协议层的业务逻辑。主要是对不同登录认证方式的请求和从服务器端得到的请求回复做处理,通过客户端选择的不同的认证方式调用不同的认证方式实现类,比如 AuthRequestByPassword 类定义了通过密码认证方式的实现。

图 6. 认证协议流程图

首先,开启一个线程用来接收从服务器发送的加密数据包,然后对这个数据包做算法解密处理并放到一个模型化的堆栈 (Packet List),而另一个线程会监听当前的 Packet List 里是否有可用的数据包,并对其做解析处理包括对数据包是否合法、是否满足某种认证算法等。如果数据包所包含的认证方式和当前客户端请求的认证方式不匹配,那么,客户端就会失去服务器的连接。反之,如果客户端请求的认证方式包含在服务器开启的认证方式,客户端会返回给服务器一个成功请求,并建立连接会话。

无认证方式(none authentication),这种认证方式通常是在第一次请求发送的时候使用的,因为通过这个认证方式,我们可以得到当前服务器端支持的所有认证方式的列表,通过这个列表我们就可以验证我们想要使用的认证方式是否被服务器端所支持。当然,如果远程目标机器支持这种 none 认证方式,那么客户端就直接得到了一个会话连接,但是这种认证方式是 SSH 协议里所不推荐使用的。

实现代码如下:

/** * 取得指定服务器名称和用户名的认证消息 * @return request - 返回一条十六进制消息 * */ public byte [] getRequestMessage() { byte [] request; ProcessTypes type = new ProcessTypes(); type.asByte(AuthConstant.SSH_MSG_USERAUTH_REQUEST); type.asString(userName); type.asString(serviceName); type.asString(AuthConstant.SSH_NONE_AUTHENTICATION_METHOD); request = type.getBytes(); return request; }

}

从流程图 6 中可以看出,当我们发送一个 none 认证方式的时候,如果服务器不支持 none 认证,那么客户端就可以取得服务器端的认证方式列表。首先解析服务器端返回的包信息,例如:

[51,34,112,98,108,105,99,107,121,44,103,119,109,111,100,0]

经过客户端的算法解析之后,我们可以得到含有如下信息的数据包:( 对于算法原理的具体说明是定义在传输层协议里,不是本文所讨论的范围。)

代码 51,说明用户验证请求失败。

从第 5 位到第 34 位记录了所当前服务器所支持的认证方法,解析后可得到 publickey,gssapi-with-mic,password 的一个由逗号隔开的认证方式字符串。

最后一位 0 表示,当前的请求失败,但并不是说整个的连接就断掉了。

解析数据包的具体算法如下:

对于服务器端来说,它要对客户端的请求作一反馈,从而说明当前的请求是否成功。

数据格式如下:

所以,这就正好解释了上述,从服务器端得到的数据解析结果。

实现部分代码如下:

当客户端得到了这个 authentications 数组之后,客户端就可以验证当前用户使用的远程登录认证方式是否是服务器所支持的。如果是那么再发送一条匹配的认证方式,从而返回登录认证成功,否则失败并打印出合理的错误信息。下面用 password 的认证方式为例做进一步说明。

对于 password 认证方式来说,它的数据请求格式如下:

具体类的实现方式和 none 认证类的实现类似,只是 getRequestMessage() 方法所有不同。

实现代码:

在这里我们需要提供给服务器端一个用户口令,这个口令会在发送给服务器端之前被进行算法加密的处理。调用 password 认证方式的代码如下:

客户端首先会做初始化操作,包括数据加密算法的协商、得到服务器端支持的认证方式等。其次客户端会检查当前用户使用的登录认证方式是否合法,然后再发送一个请求给服务器端,告诉服务器当前使用 password 认证进行远程登录。最后,服务器会返回一个数据包,里面包含了对这个请求的回复,如果验证成功,那么连接就可以开启一个安全的会话了。至此,password 认证方式的解析就完成了,接下来用户就可以对远程机器做操作了,这部分的具体说明是在 SSH 的连接层协议里,不是本文的讨论范围。

篇幅所限,本文就以 password 的认证方式为例进行了客户端远程登录的认证方式的讨论,对于其他认证方式会在以后的文章中讨论。在客户端用 SSH 协议进行远程登录的时候,提供了很多常见的认证方式,每种认证方式发送的数据包的数据结构略有不同,同时也提供了对外扩展接口,可以自定义认证方式。通过对本文的阅读,可以初步了解到,SSH 协议在用户认证层的基本原理,希望能对读者在以后的项目开发中,对 SSH 协议的使用有所帮助。

原文:http://www.ibm.com/developerworks/cn/java/j-lo-sshauthentication/

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


背景:我已经有一个ssh公钥和私钥了,绑定的是公司的码云但是绑定github是不允许的所以我需要在生成一个公钥和私钥第一步执行下面的命令, 至于如果生成ssh公钥点击这里ssh-keygen-trsa-C'your_email@example.com'-f~/.ssh/id_rsa_github然后一路回车 这里注意id_srs_g
在服务器程序的部署运维过程中,我们经常需要将文件从一个服务器拷贝到另一个服务器中。可以使用ftp,可以使用samba服务,这里我们介绍scp命令进行文件的拷贝和传输。scp是securecopy的缩写,scp是linux系统下基于ssh登陆进行安全的远程文件拷贝命令。scp是加
#!/bin/bash#创建一个以.sc结尾的文件,把要操作的主机按顺序填写进去,多个IP另起一行顶格填写例如:#192.168.0.1#192.168.0.2#确保当前操作脚本的主机,已经可以免密到被操作主机,如未完成请自行解决。do_command(){hosts=`sed-n'/^[^#]/p'*.sc`forhost
打开终端安装openssh-server软件包:sudoaptupdatesudoaptinstallopenssh-server安装完成后,SSH服务默认自动启动,你可以通过以下命令校验服务运行状态:sudosystemctlstatusssh如果防火墙开启,则需要让防火墙允许ssh通过sudoufwallowssh注意事项VMware虚拟
环境centos7.9,.NET5一、Jenkins搭建1)下载Jenkins的war包在\home目录建一个jenkins目录放jenkins的包#进入\home目录cd\home#创建jenkins目录mkdirjenkins在jenkins目录下载war包#进入jenkin目录cd\home\jenkins#下载jenkins的war包wgethttp://mirrors.jenkin
dropbear下载地址:https://matt.ucc.asn.au/dropbeareleases/dropbear-2020.81.tar.bz2软件版本号说明opensuse 15.3 ssh8 dropbear2020.81     安装编译器和依赖:zypperinstallzlib-develgcc配置安装目录:./configure--prefix=/
1.前言前面基本上已经都讲完了MHA的原理部分,这小结主要是动手实操一下MHA2.前提准备1.首先下载MHA软件包(1)#下载mha软件mha官网:https://code.google.com/archive/p/mysql-master-ha/github下载地址:https://github.com/yoshinorim/mha4mysql-manager
前期准备确定服务器可以上网apt源配置完毕安装ssh使用apt安装openssh服务。sudoapt-getinstallopenssh-server启动sshroot@cka01:~#sudo/etc/init.d/sshstart#确定22端口存在并存活root@cka01:~#ss-tnl|grep22LISTEN01280.0.0
1.首先你需要在github上或者gitlab上建立了自己的账户,项目组已经将你加入了group。2.打开gitbash,输入命令ls-al~/.ssh如果显示如下图:则表示生成过key,可以去执行第4个步骤。否则的话执行第三个步骤生成key  3.这个时候输入命令ssh-keygen-trsa-C"min~~~~"  这
简述Linux如何远程拷贝,限速和断点续传scp命令 –远程拷贝文件scp拷贝本地文件filename到远程机器192.168.188.188服务器的/datamp目录下scp-P61204-l40000filenameusername@192.168.188.188:/datamp/ -PportSpecifiestheporttoconnecttoontherem
最近两天发现push代码到GitHub上时,发现必须得用SSH或者Token的方式。直接上干货1.SSH方式 1.1在桌面上GitBashHere 1.2检查是否已存在SSH   如果已存在,则直接进入.ssh目录1.3不存在,则创建一个SSHkey(如果不需要设置输入密码,一直回车就好)$ssh-keygen
安装命令yuminstallopenssh-clientsLinuxscp命令用于Linux之间复制文件和目录。scp是securecopy的缩写,scp是linux系统下基于ssh登陆进行安全的远程文件拷贝命令。scp是加密的,rcp 是不加密的,scp是rcp的加强版。语法scp[-1246BCpqrv][-ccipher][-F
1.环境介绍1.本地为windows2.远程为linux2.本地安装ssh环境我这里下载了git,所以在环境变量里把/git/usr/bin加进去就可以了3.本地vscode安装远程开发插件Remote-development是一个集成插件,安装它就可以了4.生成ssh秘钥对,并将公钥放入远程机#本地机生成秘钥对$s
文章链接故障表现在使用jumperver登录AWSec2实例的时候发现ssh配合秘钥登录的时候无法登录,具体报错如下:ssh-i/path/xx.pemuser@10.0.11.190Permissiondenied(publickey,gssapi-keyex,gssapi-with-mic).问题排查过程在发现无法登录的第一时间等了AWS平台查
1.给root用户设置密码sudopasswdroot2.修改sshd配置文件sudonano/etc/ssh/sshd_config修改PermitRootLoginyes把PermitRootLoginwithout-password或者PermitRootLoginprohibit-password改为PermitRootLoginyes,注意PermitRootLoginwithout-password可能被注
手上有一台12.4的ios机器,通过SecureCrt可以ssh上去,但是每次连接的时候都会报“KeyboardInteractive”错误,skip即可,但是通过ssh客户端连接,却无法正常连接,错误提示如下:@127.0.0.1:Permissiondenied(publickey,password,keyboard-interactive) 开始以为是KeyboardInteract
1、创建私有CA并进行证书申请。1.创建CA所需要文件#生成证书索引数据库文件touch/etc/pki/CA/index.txt#指定第一个颁发证书的序列号echo01>/etc/pki/CA/serial2、生成CA私钥cd/etc/pki/CA/(umask066;opensslgenrsa-outprivate/cakey.pem2048)3、生成CA自签名证书op
克隆两台虚拟机加master三台组成一个集群 所克隆的虚拟机需要修改主机名,ip 永久修改主机名 hostnamectlset-hostnamenode1或node2 ip 方式1: 通过可视化界面直接修改 方式2: vim/etc/sysconfigetwork-scripts/ifcfg-ens33 然后重启网络:servicenetworkrestart
SSH配置文件中加密算法没有指定,默认支持所有加密算法,包括arcfour,arcfour128,arcfour256等弱加密算法。但是目前RC4是不安全算法若数据库安全性要求比较高,这个漏洞还是必须要修复的,下面记录下OracleRAC修复过程,此修复过程不影响现有系统。如有不当欢迎斧正。1、root权限用户才能
问题:通过XShell等客户端使用ssh方式通过root用户连接Ubuntu虚拟机时,出现SSH服务器拒绝了密码,请再试一次。解决:安装ssh,开启root用户登录权限。1安装ssh-serverroot@ubuntu:/etc/apt#apt-getinstallopenssh-server安装ssh-server2安装ssh-clientroot@ubuntu:/etc/apt#ap