SSH是一种协议标准,它的主要目的是实现远程登录和提供安全网络服务。它的实现有很多种,最常用的就是开源openssh。
对称加密和非对称加密
在讲解SSH实现原理之前,我们先来了解下加密方式,我们都知道为了数据的安全,数据在互联网上传输肯定是要加密。那加密又要分为两种加密方式:
- 对称加密(秘钥加密)
- 非对称加密(公钥加密)
对称加密,就是加密和解密都是使用同一套秘钥。看下图所示:
服务端和客户端的交互过程如下图:
对称加密的加密强度很高,但是这有一个很大的问题。就是:如何保证秘钥A的安全?当客户端的数量非常大的时候,如何保证秘钥的安全?一旦秘钥泄漏出去,后果不堪设想。用户的安全就没有任何保障。所以非对称加密的出现就为了弥补这一点。
非对称加密有两个秘钥:“私钥”和“公钥”。公钥加密后的密文,只能通过对应的私钥进行解密。而通过公钥推理出私钥的可能性微乎其微。下图展示的是基本原理:
上图在实际的使用中存在一个问题,就是客户端需要知道服务端的公钥,不然没法加密。所以需要服务端告知客户端公钥的一个过程。如下图:
- 服务端收到客户端的登录请求,服务端把公钥发送给客户端
- 客户端用这个公钥,对密码加密
- 客户端将加密后的密码发送给服务端
- 服务端用私钥解密,验证OK
- 返回验证结果
私钥是服务端独有,这就保证了客户端的登录信息即使在网络传输过程中被窃据,也没有私钥进行解密,保证了数据的安全性,这充分利用了非对称加密的特性。
你觉得这样就安全了吗?
上述图中有一个漏洞:客户端如何保证接受到的公钥就是目标服务端的?如果攻击者截获了客户端的请求,发送自己的公钥,那客户端用这个公钥加密的密码,就能被攻击者用自己的私钥解密。这不是一个很大的漏洞吗?
SSH如何做的?
SSH有两种方式:
- 基于口令的认证;
- 基于公钥认证
1. 基于口令的认证
从上面可以知道,我们的主要要解决的是“如何对服务端的公钥进行验证”,客户端只要对公钥进行确认下就OK了。通常在第一次登录的时候,系统会出现下面提示信息:
- he 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后,该host已被确认,并被追加到文件known_hosts中,然后就需要输入密码。
2. 基于公钥认证
- 客户端与服务端协商产生会话密钥;
- 客户端会向服务端发送一个登录请求(如:root@192.168.1.2),发送的信息包括用户名root和root的公钥指纹,且所有信息都是通过会话密钥加密过的。
- 服务端通过会话密钥解密客户端发送的数据得到请求登录的用户名root和root的公钥指纹,然后读取root用户家目录下的所有公钥数据(/root/.ssh/autorized_keys文件中),并分别通过单向加密算法获取各公钥的数据指纹与客户端发送过来的数据指纹做对比,从而找到客户端上的root用户的公钥;
- 服务端使用找到的客户端的公钥对一个随机数进行加密发送发送给客户端;
- 客户端使用私钥对服务端发送的随机数密文进行解密,然后把解密结果发送给服务端;
- 服务端验证客户端解密后的数据与自己发送的数据一致,则对客户端身份验证成功;