SSH连接服务器的原理理解

        在说SSH连接服务器之前先说下非对称加密RSA的理解,我也不记得我之前的博客是否有记录此理解。在查了一些SSH连接服务器的资料后发现有些人对RSA的理解有些出入,下面我先树下我自己对RSA的理解,分几点阐述:

  • RSA分为公钥和私钥,公钥可以给出去,任何人都能拿到,公钥主人也不怕别人拿到
  • 私钥主人自己保护好私钥,千万不能让别人拿到你的私钥
  • 私钥签名,公钥验签,这个用法是不能倒过来的,这个主要用于验证些数据data是拥有私钥的主人发出来的,任何人都可以拿着主人之前给出的工艺对信息进行验证,例如电子签名,就是RSA的这种用法
  • RSA的加解密用法就是用公钥加密数据,然后用私钥来解密数据,这个也不能倒过来,而且RSA的加解密用法只能这么用,因为公钥加密的数据只有私钥才能解密

        好了,上面的理解大致就是这样,总结一下:非对称加密算法RSA有两种用法,分别是签名验签和加解密用法。然后下面来说说SSH连接服务器的原理。SSH连接服务器有两种方式,分别是通过账户密码进行连接和通过公钥进行连接。

1、通过账户密码登陆

这种方式是比较传统的方式,直接命令行“ssh user@ip”,输入密码即可连接对应ip地址的服务器。连接的时候原理如下:

如果你是第一次登录对方主机,系统会出现下面的提示:

 $ ssh user@host
  The authenticity of host 'host (12.18.429.21)' can't be established.
  RSA key fingerprint is 98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d.
  Are you sure you want to continue connecting (yes/no)?

        这段话的意思是,无法确认host主机的真实性,只知道它的公钥指纹,问你还想继续连接吗?所谓"公钥指纹",是指公钥长度较长(这里采用RSA算法,长达1024位),很难比对,所以对其进行MD5计算,将它变成一个128位的指纹。上例中是98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d,再进行比较,就容易多了。

        很自然的一个问题就是,用户怎么知道远程主机的公钥指纹应该是多少?回答是没有好办法,远程主机必须在自己的网站上贴出公钥指纹,以便用户自行核对。但是我们平时也没注意那么多,直接输入yes就直接连接了,并输入了密码。

        当远程主机的公钥被接受以后,它就会被保存在文件$HOME/.ssh/known_hosts之中。下次再连接这台主机,系统就会认出它的公钥已经保存在本地了,从而跳过警告部分,直接提示输入密码。每个SSH用户都有自己的known_hosts文件,此外系统也有一个这样的文件,通常是/etc/ssh/ssh_known_hosts,保存一些对所有用户都可信赖的远程主机的公钥。

        SSH连接的整个过程是这样的:

        (1)远程主机收到用户的登录请求,把自己的公钥发给用户。

        (2)用户使用这个公钥,将登录密码加密后,发送回来。

        (3)远程主机用自己的私钥,解密登录密码,如果密码正确,就同意用户登录。

如下图所示

 SSH连接服务器的原理理解_第1张图片

         从上面的流程可以看出连接过程使用的是RSA非对称算法的加解密功能,级即公钥加密,私钥解密。而且该密钥对是服务器端的密钥对,服务端将公钥给客户端,客户端使用公钥加密账户密码,然后服务器使用私钥进行解密。

        这个过程本身是安全的,但是实施的时候存在一个风险:如果有人截获了登录请求,然后冒充远程主机,将伪造的公钥发给用户,那么用户很难辨别真伪。因为不像https协议,SSH协议的公钥是没有证书中心(CA)公证的,也就是说,都是自己签发的。可以设想,如果攻击者插在用户与远程主机之间(比如在公共的wifi区域),用伪造的公钥,获取用户的登录密码。再用这个密码登录远程主机,那么SSH的安全机制就荡然无存了。这种风险就是著名的中间人攻击。后面又出现公钥的登陆方式,可以防止这种情况发生。

 2、通过公钥进行免密登陆

        这种登陆的前提是客户端需要生成一对密钥,将公钥放到需访问的远程服务器。这种验证比上一种的好处是,不能仿冒真正的服务器,因为要仿冒必须拿到客户端生成的公钥。使用公钥免密登陆的大致流程如下,这里不做过多解释,因为网上的教程实在是太多了:

  • 客户端使用命令ssh-keygen生成一对公私钥
  • 运行结束以后,在$HOME/.ssh/目录下,会新生成两个文件:id_rsa.pub和id_rsa。前者是你的公钥,后者是你的私钥。
  • 然后将公钥id_rsa.pub里面的公钥追加拷贝到对应服务的$HOME/.ssh/authorized_keys文件中去。

        然后操作完成,用户就可以在命令行执行命令“ssh user@ip”连接服务器,此时就不需要输入密码了,实现了免密登陆。

        能够实现公钥免密登陆,其公钥登陆的原理如下所示:前提是上面的准备工作已经完成。

        (1)客户端发送连接,并将自己生成的公钥发给服务端

        (2)服务器收到公钥,拿着此公钥到$HOME/.ssh/authorized_keys文件中去比对是否存在该公钥,如果有的话,就生成一段随机数挑战challenge,并使用该公钥对随机数进行加密,并把密文回给客户端;如果没有的话,直接返回,重新执行账户密码的连接流程(此处我也不是很确定是不是这样,欢迎大家评论区评判指正)

        (3)客户端收到后,使用生成的私钥对密文进行解密,得到challenge的明文数据,并发给服务器

        (4)服务器收到challenge的明文数据后,和自己之前生成的进行比较,如果一样,就建立连接

连接原理流程图如下所示:

SSH连接服务器的原理理解_第2张图片

         从上面可以看出,公钥的免密登陆也是使用的是RSA的加解密功能,只是和区别在于,密钥对是客户端生成,客户端持有私钥,而且,客户端对应的公钥需要提前预置到服务器的$HOME/.ssh/authorized_keys文件中去。

备注1、有时候服务器没有安装SSH的server,需要在命令行进行安装

备注2、有些文件可能权限问题无法进行公钥连接,只需要配置下权限即可,网上教程也有很多

2022年2月23日更正:

使用公钥登录的时候好像应该是下面的流程,不知道到底是哪一个,记录一下,不过好像下面这个流程更安全一些:

  1. 客户端首先向服务器发送它想要验证的密钥对的 ID。
  2. 服务器检查authorized_keys客户端尝试登录的帐户文件以获取密钥 ID。
  3. 如果在文件中找到匹配 ID 的公钥,服务器会生成一个随机数并使用该公钥加密该数字。
  4. 服务器向客户端发送此加密消息。
  5. 如果客户端确实拥有相关的私钥,它将能够使用该密钥解密消息,从而显示原始数字。
  6. 客户端将解密后的数字与用于加密通信的共享会话密钥相结合,并计算该值的 MD5 哈希值。
  7. 然后,客户端将此 MD5 散列发送回服务器,作为对加密数字消息的答复。
  8. 服务器使用相同的共享会话密钥和它发送给客户端的原始数字来自行计算 MD5 值。它将自己的计算与客户端发回的计算进行比较。如果这两个值匹配,则证明客户端拥有私钥并且客户端已通过身份验证。

这个流程和之前的流程最大的区别是他不会将解密的随机数challenge明文发送回服务器端,而是通过和会话密钥结合生成MD5,这样又避免了数据泄露的风险,感觉这歌交互更加严谨,欢迎大家评论区讨论。

3、总结与探讨:

  • 不管是账户密码的SSH登陆还是公钥的免密登陆,都只是用到了RSA的加解密功能,即使用公钥加密,然后私钥解密的功能,整个过程完全没有用到签名验签的功能。
  • 我有个地方是这样理解的,不知道对不对,欢迎大家探讨。就是你本来使用的是账户密码登陆的服务器,但是后来又使用公钥进行了配置,实行了免密登陆。那么当你命令行输入了登陆命令“ssh user@ip”连接服务器时,ssh怎么知道你是要密码登陆还是公钥免密登陆呢,我的理解是SSH机制应该是会先检测再执行,我画了个流程图,大家可以看看理解的对不对:

SSH连接服务器的原理理解_第3张图片

好了,之后如果有些地方理解的不对的地方再来修改。 

2022年2月23日补充

4、密钥协商

        后面看了更详细的SSH资料后,发现SSH是非常安全的一种远程连接,其主要还是整个传输层是加密传输的。下面我来补充下认证之前的传输加密过程。

        在SSH认证之前主要存在两个大的步骤,如下

  • SSH协议版本协商阶段。SSH目前包括SSH1和SSH2两个大版本。
  • 密钥和算法协商阶段,SSH支持多种加密算法,双方根据自己和对端支持的算法进行协商,最终决定要使用的算法

1)协议协商版本,其主要是为后面加密选择同一种加密算法等做铺垫,起主要流程如下:

  • 客户端通过TCP三次握手与服务器的SSH端口建立TCP连接。(具体的TCP连接流程在网上可以自行搜索)
  • 服务器通过建立好的连接向客户端发送一个包含SSH版本信息的报文,格式为“SSH-.-<软件版本号>”,软件版本号主要用于调试。
  • 客户端收到版本号信息后,如果服务器使用的协议版本号低于自己的,但是客户端能够兼容这个低版本的SSH协议,则就使用这个版本进行通信。否则,客户端会使用自己的版本号。
  • 客户端将自己决定使用的版本号发给服务器,服务器判断客户端使用的版本号自己是否支持,从而决定是否能够继续完成SSH连接。

如果协商成功,则进入密钥和算法协商阶段

2)密钥和算法协商,其主要是计算出共识的对称算法密钥和加密算法,其主要流程如下:

  • 服务器端和客户端分别发送算法协商报文给对端,报文中包含自己支持的公钥算法列表,加密算法列表,MAC(Message Authentication Code,消息验证码)算法列表,压缩算法列表等。
  • 和版本协商阶段类似,服务器端和客户端根据自己和对端支持的算法来决定最终要使用的各个算法。
  • 服务器端和客户端利用Diffie-Hellman密钥交换算法,主机密钥对等参数,生成共享密钥和会话ID。会话密钥用于在后续的通信过程中两端对传输的数据进行加密和解密,而会话ID用于认证过程。

        密钥协商完成后,后面的认证等所有操作都使用协商出来的密钥和算法进行加密通信,保证整个通过过程的安全,而且因为每次连接时,密钥协商算法的部分参数不一样,导致每次协商的加密密钥也不一样,这样就使得整个过程更加的安全可靠。

        从上面密钥协商算法,告诉我们,SSH的客户端和服务端都含有自己的一对非对称密钥(一般是RSA),这对非对称密钥在整个算法过程中主要用来使用DH密钥交换算法计算出传输的加密密钥。这两对非对称密钥和认证的时候通过公钥登录的非对称密钥是完全两个独立的,互补干涉,各行其职。

        DH密钥交换算法的粗略理解:可以这样理解:我们把SSH客户端定义为A端,SSH服务器端定义为B端。A端和B端含有自己独有的一对公私钥对,A端使用A的私钥和B端的公钥和一个随机数C,使用算法生成密钥D1;同样的道理B端使用自己的私钥和A端的公钥和一个随机数C,使用算法生成密钥D2,只要随机数C是一样的,最后生成出来的D1和D2也是一样的,后面A端和B端都使用此密钥进行加密传输。当然每次SSH连接,随机数C肯定是不一样的,所以最后的生成的D也是不一样的,这样就会更加安全。

你可能感兴趣的:(通信理论知识,服务器,ssh,运维,非对称加密算法)