图解 SSH 原理( 二 )

如果输入 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 中,然后就需要输入密码,之后的流程就按照图 1-3 进行 。
2.1.2 基于公钥认证
 
在上面介绍的登录流程中可以发现,每次登录都需要输入密码,很麻烦 。SSH 提供了另外一种可以免去输入密码过程的登录方式:公钥登录 。流程如下:
 

图解 SSH 原理

文章插图
 
 
图1-5:公钥认证流程
  1. Client 将自己的公钥存放在 Server 上,追加在文件 authorized_keys 中 。注意:Client 端的 Public key 是 Client 手动 Copy 到 Server端的,SSH 建立连接过程中没有公钥的交换操作 。
  2. Server 端接收到 Client 的连接请求后,会在 authorized_keys 中匹配到 Client 的公钥 pubKey,并生成随机数 R,用 Client 的公钥对该随机数进行加密得到 pubKey(R),然后将加密后信息发送给 Client 。
  3. Client 端通过私钥进行解密得到随机数 R,然后对随机数 R 和本次会话的 SessionKey 利用 MD5 生成摘要 Digest1,发送给 Server 端 。
  4. Server 端会也会对 R 和 SessionKey 利用同样摘要算法生成 Digest2 。
  5. Server 端会最后比较 Digest1 和 Digest2 是否相同,完成认证过程 。
注意:在步骤1中,Client 将自己的公钥存放在 Server 上 。需要用户手动将公钥 Copy 到 Server 上 。这就是在配置 SSH 的时候进程进行的操作 。下图是 GitHub 上 SSH keys 设置视图:
 
 
图解 SSH 原理

文章插图
 
 
GitHub 中 SSH keys 设置
在步骤 2 中,Server 端根据什么信息在 authorized_keys 中进行查找的呢?主要是根据 Client 在认证的开始会发送一个 KeyID 给 Server,这个 KeyID 会唯一对应该 Client 的一个 PublicKey,Server 就是通过该 KeyID 在 authorized_keys 进行查找对应的 PublicKey 。
3. SSH 实践
3.1 生成密钥操作
经过上面的原理分析,下面三行命令的含义应该很容易理解了:
$ ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys$ chmod 0600 ~/.ssh/authorized_keysssh-keygen 是用于生产密钥的工具 。
  • -t:指定生成密钥类型(rsa、dsa、ecdsa 等)
  • -P:指定 passphrase,用于确保私钥的安全
  • -f:指定存放密钥的文件(公钥文件默认和私钥同目录下,不同的是存放公钥的文件名需要加上后缀 .pub)
首先看下面 ~/.ssh 中的四个文件:
 
图解 SSH 原理

文章插图
 
 
SSH 涉及文件
  1. id_rsa:保存私钥
  2. id_rsa.pub:保存公钥
  3. authorized_keys:保存已授权的客户端公钥
  4. known_hosts:保存已认证的远程主机 ID(关于 known_hosts 详情,见文末更新内容)
四个角色的关系如下图所示:
 
图解 SSH 原理

文章插图
 
 
SSH 结构简图
需要注意的是:一台主机可能既是 Client,也是 Server 。所以会同时拥有authorized_keys 和 known_hosts 。
3.2 登录操作
# 以用户名user,登录远程主机host$ ssh user@host?# 本地用户和远程用户相同,则用户名可省去$ ssh host?# SSH默认端口22,可以用参数p修改端口$ ssh -p 2017 user@host4. 其它一些补充
 
下面关于 SSH 的 known_hosts 机制的一些补充 。
4.1 known_hosts 中存储的内容是什么?
 
known_hosts 中存储是已认证的远程主机 host key,每个 SSH Server 都有一个 secret, unique ID, called a host key 。
4.2 host key 何时加入 known_hosts 的?
 
当我们第一次通过 SSH 登录远程主机的时候,Client 端会有如下提示:
Host key not found from the list of known hosts.Are you sure you want to continue connecting (yes/no)?此时,如果我们选择 yes,那么该 host key 就会被加入到 Client 的known_hosts 中,格式如下:
# domain name+encryption algorithm+host key
example.hostname.com ssh-rsa AAAAB4NzaC1yc2EAAAABIwAAAQEA...
4.3 为什么需要 known_hosts?
最后探讨下为什么需要 known_hosts,这个文件主要是通过 Client 和 Server的双向认证,从而避免中间人(man-in-the-middle attack)攻击,每次Client 向 Server 发起连接的时候,不仅仅 Server 要验证 Client 的合法性,Client 同样也需要验证 Server 的身份,SSH Client 就是通过 known_hosts 中的 host key 来验证 Server 的身份的 。


推荐阅读