ssh 远程连接的两种验证方式

714 阅读5分钟

SSH 为 Secure Shell 的缩写,由 IETF 的网络小组(Network Working Group)所制定;SSH 为建立在应用层基础上的安全协议。其目的是实现安全远程登录以及其它安全网络服务

从客户端来看,SSH提供两种级别的安全验证。一种是基于口令的安全验证,另一种是基于密钥的安全验证。分别看一下两种验证方式的过程。

一、基于口令的验证

1,客户端向服务端发起登录请求:ssh username@hostname

2,服务端收到客户端的请求后,把自己的公钥发送给客户端;(服务端的公钥保存在/etc/ssh/*.pub里面)

3,当客户端第一次收到该服务端发送过来的公钥时,为了防止中间人攻击(发送公钥的主机不是服务端,而是拦截了客户端登录请求的主机),客户端主机会有系统提示:

The authenticity of host 'ssh-server.example.com (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)? 

上面的信息说的是:无法确认主机ssh-server.example.com(12.18.429.21)的真实性,不过知道它的公钥指纹,是否继续连接?之所以用fingerprint代替key,主要是key过于长(RSA算法生成的公钥有1024位),很难直接比较。所以,对公钥进行hash生成一个128位的指纹,这样就方便比较了。

如果输入 yes 后,会出现如下信息:

Warning: Permanently added 'ssh-server.example.com,12.18.429.21' (RSA) to the list of known hosts. 
Password: (enter password) 

该host已被确认,并被追加到文件 known_hosts 中,然后就需要输入密码。(当 known_hosts 存储了服务端的公钥之后,客户端后续连接该服务端就会比对存储在 known_hosts 文件里的公钥,从而确认是否为该服务端发来的公钥)

4,客户端输入密码,使用服务端发来的公钥进行加密,发送给服务端;

5,服务端收到客户端的加密信息,使用自己的私钥进行解密比对,比对正确就给客户端响应。

二、基于公钥验证

1,客户端将自己的公钥放到服务端的 authorized_keys 文件中;

2,客户端向服务端发起登录请求:ssh username@hostname

3,服务端收到客户端的请求后,会在 authorized_keys 中匹配到客户端的公钥,并生成随机数 R,用客户端的公钥对该随机数进行加密,然后将加密信息发送到客户端;

4,客户端收到加密信息后用私钥进行解密,得到随机数 R,然后对随机数 R 和本次会话的 SessionKey 利用 md5 生成摘要 Digest1,发送给服务端;

5,服务端收到 Digest1 后,也会对随机数 R 和 SessionKey 利用同样的摘要算法生成 Digest2,然后对比 Digest1 和 Digest2 是否相同,完成认证过程。

三、一些补充说明

公钥和私钥到底哪个是用来加密,哪个是用来解密的,是否可以公钥加密私钥解密,同时也可以私钥加密公钥解密呢?

首先要明确两个问题:(1)既可以公钥加密私钥解密,也可以私钥加密公钥解密;(2)加密解密和签名验证是两个不同的概念。

1, 先来说加密解密:需要同时使用公钥和私钥的加密算法是非对称加密,最常见的便是RSA。

举例说明非对称加密:如果A想要给B秘密的发一条信息,只需要B创建一套公钥(盒子)和私钥(钥匙),盒子可以随意分发,但是钥匙只能B自己所有,当A想要给B发信息时,只需要把信息(纸条)通过B的公钥加密(放入盒子里锁上),再由B用私钥(钥匙)进行解密(打开盒子),即可获取A发送的信息。此时如果C想要截取信息,但是由于没有B的私钥,C即使拿到了信息也无法解密(只有盒子没有钥匙),从而保证了数据的安全性。 那么B是否可以通过私钥加密信息,然后由A使用公钥解密信息呢?从原理上讲,是可以的。 非对称密钥是可以用于双向加解密的。但是我们为什么不这么用呢,很好理解,因为所谓公钥,是公开的,不只A一个人拥有,因此虽然A能够正常读取到信息,但是其他人也可以解密该条信息,从而无法保证信息的安全性。但是签名验证就不同了。

2, 签名验证:用私钥进行签名,用公钥进行验证,从而保证信息来源是私钥拥有者。

举例说明:A想要让B确认某条信息是由自己发出的,先将自己的公钥发送给B,然后用自己的私钥对信息进行签名并发送给B(比如将字符串X用A的私钥加密生成Y,将X和Y以及信息都发送给B),B收到信息后用A的公钥对签名进行验证,用A的公钥解密Y得到Z,如果Z=X,则验证成功,说明信息是由A发布的。