ssh 服务的原理

2019/08/12 ssh Linux

ssh 服务的原理

读者大可以直接就自己的问题去 Google 解决方案,但是不理解这个过程,那么每次遇到都要去 search,自己只是‘工具人’,遇到了问题也不知道如何是好。这时候需要看下原理,有原理做基础,才能理解做配置的每一步的意义。

两种安全验证

SSH(即 Secure Shell),是一项创建在应用层和传输层基础上的安全协议,为计算机 Shell 提供安全的传输和使用环境。

所以为了安全,SSH 提供了两种级别的安全认证,基于密码的安全认证和基于密钥的安全认证。

基于密码的安全认证

基于密码的安全认证,登录的时候需要提供账号和密码;远程主机将自己的公钥分发给登录客户端,客户端访问主机使用该公钥加密;远程主机使用自己的私钥解密数据。

登录的流程如下:

  • 远程主机收到用户登录请求,将自己的公钥发给用户
  • 用户通过远程主机公钥的指纹确认主机的真实性,然后使用远程主机公钥将登录密码加密后,发送回远程主机
  • 远程主机使用自己的私钥解码登录密码,验证密码正确后,允许用户登录

这种就是最常用的直接登录,需要输入密码,而传入过程中,明文密码会被加密,所以很安全。

基于密钥文件的安全认证

基于密钥的安全认证,客户端将将公钥上传到服务器。登录的时候,客户端向服务器发送登录请求;服务器收到请求后,向用户发送一段随机字符串;用户用自己的私钥加密后,再发送回服务器;服务器使用事先存储的公钥进行解密,如果解密成功,证明用户可信,允许登录。

这种方式,在登录服务器的过程中,不需要上传密码,增加了安全性。

known_hosts 文件

当第一次登陆远程主机时,不管是用密码还是密钥,都会有个提示:

$ ssh user@host
The authenticity of host 'host (***.***.***.***)' 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)?

这段话提示用户无法确认远程主机的真实性,只知道 RSA 公钥的指纹,询问用户是否继续。

我们使用 ssh-keygen 工具可以生成 SSH 密钥对,其中公钥的长度可以很长,对用户来说不方便直接对比验证,因此对其进行了 MD5 计算,生成了一个128的指纹,这样再进行比较就比较容易了。

那么这里就要求我们事先知道远程主机的公钥指纹,才可以确认主机的真实性。

用户确认主机的真实性,输入 yes 继续连接:

Warning: Permanently added 'host,***.***.***.***' (RSA) to the list of known hosts.

然后输入密码:

Password: (enter password)

密码正确,即可登录成功。

当第一次登录成功后,远程主机的公钥会被保存到文件 $HOME/.ssh/known_hosts 中,下次再连接这台主机就会跳过警告,直接提示输入密码。

每个SSH用户都有自己的known_hosts文件,此外系统也有一个这样的文件,通常是 /etc/ssh/ssh_known_hosts ,保存一些对所有用户都可信赖的远程主机的公钥。

所以 known_hosts 文件保存的就是 远程主机的公钥指纹 的合集。如果远程主机的公钥变了,那么常规的ssh连接就会遇到下面的错误,此时清理掉该文件就好了。

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@  WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!  @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

authorized_keys 文件

那么 authorized_keys 文件又是什么呢?如果要做到免密登陆某些机器,就必须要用到这个文件。

我们上传公钥到服务端,即将公钥内容附加到服务器用户目录下的 $HOME/.ssh/authorized_keys 文件。

也就是说,远端服务器的 authorized_keys 有自己主机的公钥,那么在 ssh 登陆的时候 -i 指定自己主机的密钥就可以免密登陆了。

密钥对的生成

SSH 密钥对可以让用户无需输入密码即可登录到 SSH 服务器中。由于登录的过程不需要密码,因此可以防止由于密码被拦截、破解造成的账户密码泄露。再加上密码短语(passphrase)的使用,使得 SSH 的安全性更高一层。

SSH 密钥对总是一把公钥、一把私钥的成对出现;公钥可以自由的添加到远程 SSH 服务器中用来验证用户是否合法;私钥相当于自己的身份认证,需要妥善保存不能泄露。

SSH 密钥的其使用原理很简单:用户将公钥添加到远程主机中,登录的时候,远程主机会向用户发送一段随即字符串,用户使用自己的私钥加密后,再发送到远程主机。远程主机使用本地存储的公钥进行解密,如果成功,证明用户时可信的,直接允许登录 shell ,不再要求密码。这样就保证了整个登录过程的安全,防止了中间人攻击。

生成密钥对

ssh-keygen 命令

我们可以使用 ssh-keygen 命令来生成密钥对:

$ ssh-keygen -t ecdsa -b 512 -C "$(whoami)@$(hostname)-$(date -I)"
Generating public/private ecdsa key pair.
Enter file in which to save the key (/home/username/.ssh/id_ecdsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/username/.ssh/id_ecdsa.
Your public key has been saved in /home/username/.ssh/id_ecdsa.pub.
The key fingerprint is:
dd:15:ee:24:20:14:11:01:b8:72:a2:0f:99:4c:79:7f username@localhost-2015-03-08
The key's randomart image is:
+--[ECDSA  521]---+
|     ..oB=.   .  |
|    .    . . . . |
|  .  .      . +  |
| oo.o    . . =   |
|o+.+.   S . . .  |
|=.   . E         |
| o    .          |
|  .              |
|                 |
+-----------------+

其中可使用

  • -t 指定加密算法
  • -b 自定生成密钥长度
  • -C 添加密钥对的说明comment。
  • -f 指定生成的私钥存储的文件全路径名称

生成的密钥对默认存储在用户目录下的 .ssh 目录中,私钥默认名称为 id_*** (即 id_ + 加密算法名称)。私钥对应的公钥文件为 私钥文件全名称 + .pub

上面例子中创建了一对长度为 512 位的椭圆加密算法(ECDSA)加密的密钥对。创建 SSH 密钥对可选择多种加密算法,例如 RSA 、 DSA 、 ECDSA 等。

密码短语(Passphras)

密码短语(passphras)是一连串的单词或文本组成,用来控制对电脑系统的访问。它的用法类似于密码(Password),但是通常会比密码长度更长,这样就增加了破解的复杂度。密码短语不同于密码,它可以是有实际意义的一段话,便于用户记忆。

密码短语默认可以不创建,但是这会导致不安全性。私钥是未经加密存储在电脑上的,电脑遗失或被窃取后,任何人拿到你的私钥后都可以随意访问 SSH 服务器;另外,电脑的 root 用户有权限访问电脑上的任意文件,这也包括你的私钥文件。因此,为了提高安全性还是建议用户设置自己的密码短语。

已经生成的密钥对也可以修改密码短语。假设使用的是 RSA 加密的密钥对,存储到默认路径,输入以下命令即可:

# ssh-keygen -f ~/.ssh/id_rsa -p

SSH agent

SSH agent 是 OpenSSH 或其它 SSH 程序提供的一个程序,提供了存储私钥的安全方法。如果用户的私钥使用了密码短语来加密的话,那么每一次使用 SSH密钥进行登录时,都需要用户输入正确的的密钥短语。而 SSH agent 程序能够将已经解密的私钥缓存起来,在需要的时候提供给 SSH 客户端,这样用户只需要在将私钥加入 SSH agent 缓存的时候输入一次密码短语就可以了。

首先确保当前 SSH agent 可用:

# start the ssh-agent in the background
$ eval "$(ssh-agent -s)"
Agent pid 29393

ssh-add

添加 SSH 密钥到 SSH agent:

$ ssh-add ~/.ssh/id_rsa
Enter passphrase for /home/username/.ssh/id_rsa:
Identity added: /home/username/.ssh/id_rsa (/home/username/.ssh/id_rsa)

查看 SSH agent 缓存密钥列表:

$ ssh-add -l
2048 b9:a7:f0:44:a5:47:79:a5:ff:9d:14:5c:d3:78:04:65 /home/username/.ssh/id_rsa (RSA)

测试连接

将 SSH 公钥添加到 SSH 服务端后,就可以使用 SSH 来连接远程主机了。下面以 GitHub 为例测试连接:

$ ssh -T git@github.com
Hi username! You've successfully authenticated, but GitHub does not provide shell access.

这说明连接成功了。

Search

    Table of Contents