计算机网络协议系列 加密的远程登录协议 ssh 使用及底层原理探究

- 1 min

计算机网络协议系列(二十六)

基本使用

TELNET 无需任何认证即可发送内容,容易造成通信窃听和非法侵入的危险。SSH 是英文 Secure Shell 的简写,顾名思义,可以加密通信内容,是加密的远程登录协议,通过在网络中建立安全隧道来实现 SSH 客户端与服务器之间的连接,可以在不安全的网络中为网络服务提供安全的传输环境。

SSH 本身是一种协议,有多种实现,最常见的就是开源的 OpenSSH,我们在日常使用过程中最多的场景就是通过它来实现远程登录,既可以在终端直接通过 ssh 命令登录远程主机:

ssh <用户名>@<主机名或IP地址>

比如,要以 root 身份登录主机名为 homestead 的机器,可以通过 ssh root@homestead 进行连接。如果需要密码验证的话,下一步会提示你输入密码。

也可以通过客户端工具比如 PuTTYXshellSecureCRT 等进行远程操作:

img

服务器上有对应的后台守护进程 sshd 响应客户端 SSH 远程连接,默认监听端口号是 22,当然,你也可以自定义这个端口号然后在连接时通过 -p 选项指定:

ssh -p 2222 root@homestead  // 远程 sshd 端口号是 2222

关于 SSH 的基本使用就是这样,比较简单,登录成功后,即可通过命令行在远程主机上进行操作和配置。下面我们来看看 SSH 协议的原理,它是如何确保传输通道的安全的。

SSH 底层原理

SSH 之所以能够保证安全,原因在于它采用了公钥加密。

整个过程是这样的:

  1. 远程主机收到用户的登录请求,把自己的公钥发给用户;
  2. 用户使用这个公钥,将登录密码加密后,发送回来;
  3. 远程主机用自己的私钥,解密登录密码,如果密码正确,就同意用户登录。

这个过程本身是安全的,但是实施的时候存在一个风险:如果有人截获了登录请求,然后冒充远程主机,将伪造的公钥发给用户,那么用户很难辨别真伪。因为不像 HTTPS 协议,SSH 协议的公钥是没有认证中心(CA)公证的,也就是说,都是自己签发的。

可以设想,如果攻击者插在用户与远程主机之间,用伪造的公钥,获取用户的登录密码,再用这个密码登录远程主机,那么 SSH 的安全机制就荡然无存了。这种风险就是著名的「中间人攻击」。

SSH 协议是如何应对这种攻击的呢?实际上,在通过 SSH 首次进行远程登录的时候,系统会要求你比对返回的公钥是否与目标服务器上的公钥信息一致。

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

img

意思是无法确认远程主机的真实性,只知道它的公钥指纹,问你是否还想继续连接。之所以提示 ECDSA 类型的公钥指纹,是因为指纹比公钥的长度要短,所以更容易比较。

那怎么知道远程主机的公钥指纹应该是多少?这个可以通过 ssh-keyscan 命令结合 ssh-keygen 得到。ssh-keyscan 命令可获取服务器公钥:

ssh-keyscan -t ECDSA -p 22 laravelacademy.org

而 ssh-keygen 命令可以计算公钥的指纹:

ssh-keygen -E sha256 -lf ~/.ssh/known_hosts

只要计算一下服务器上的相应公钥的指纹,并与客户端获取的指纹进行比对一致,就能确定连接的是否是公钥对应的服务器。

> 注:某些 SSH 终端默认提供的是 MD5 格式的公钥指纹,此时,只需将 -E 指定的参数设置为 md5 即可。

如果输入 yes 确认,则系统会提示远程主机已经得到认可:

Warning: Permanently added 'laravelacademy.org,114.215.241.29' (ECDSA) to the list of known hosts.

同时服务器 SSH 公钥会添加到本地的 ~/.ssh/known_hosts 文件里面。然后终端会提示你输入密码登录远程主机:

xueyuanjun@laravelacademy.org's password:

如果密码正确,就可以登录了。下次再连接这台主机,由于 ~/.ssh/known_hosts 文件里已经包含了对应的公钥信息,就会跳过警告部分,直接提示输入密码。

一般而言,系统中每个用户都有自己的 known_hosts 文件,此外还有一个系统级的 /etc/ssh/ssh_known_hosts 文件,用于保存对所有用户都可信赖的远程主机的公钥。

使用公钥登录

每次都要输入密码登录,有些繁琐,你还可以配置每次直接使用公钥进行登录,所谓「公钥登录」,原理很简单,就是用户将自己的公钥储存在远程主机上。登录的时候,远程主机会向用户发送一段随机字符串,用户用自己的私钥加密后,再发回来。远程主机用事先储存的公钥进行解密,如果成功,就证明用户是可信的,直接允许登录,不再要求密码。

rss facebook twitter github gitlab youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora quora