SSH 协议分析
SSH(Secure Shell)即安全外壳协议,是一种位于应用层的加密的网络传输协议,虽然任何网络服务都可以通过 SSH 实现安全传输,但其最常见的用途还是远程登录,是 Telnet 等非安全 Shell 的替代品。
OpenSSH 的运行机制
SSH 是一种协议,其实现多种多样,目前使用最广泛的实现是 OpenSSH 项目。当使用 ssh user@host
命令进行登录时,所完成的整个过程如下:
- 远程主机收到用户的登录请求,把自己的公钥发给用户
- 用户使用这个公钥,将登录密码加密后,发送给远程主机
- 远程主机用自己的私钥,解密登录密码,若密码正确,则同意用户登录
- 后续过程中,用户发送的信息都采用此方式进行加密发送
因为不像 HTTPS 协议,SSH 协议的公钥是没有证书中心(CA)公证的,所以为了防止中间人攻击,当用户第一次登录远程主机时,系统会提示如下信息:
1 | The authenticity of host 'host (12.18.429.21)' can't be established. |
即系统无法确认远程主机的真实性(远程主机有可能是中间人),只知道远程主机的公钥指纹,询问用户是否继续连接。公钥指纹就是对公钥进行哈希计算得到的,为了方便用户的比较。用户并没有什么好的办法得知自己想要连接的真实远程主机的公钥指纹,一个可行的办法是远程主机在其官方网站上贴出自己的公钥指纹,方便用户和系统提示的指纹进行比较。
假定当用户进行风险衡量后决定继续连接,接下来的过程就如上述提到的一样。远程主机的公钥会被保存在 $HOME/.ssh/known_hosts
文件中,当用户下次再连接时,系统就会认出它的公钥已经保存在本地了,从而跳过警告部分,直接提示输入密码。
除了采用口令登录外,还可使用公钥登录,原理为:用户将自己的公钥储存在远程主机上,登录时,远程主机会向用户发送一段随机字符串,用户用自己的私钥加密后,再发回来,远程主机用事先储存的公钥进行解密,如果成功,就证明用户是可信的,直接允许登录 shell,不再要求密码。
OpenSSH 提供了一个工具 — ssh-keygen
,使用它可以方便的生成一对公私钥,生成的公钥为 id_rsa.pub
,私钥为 id_rsa
,保存在 $HOME/.ssh
目录下,当然你可以使用 -t
(type)参数指定密钥的类型(默认生成类型为 RSA),使用 -f
(file)参数指定生成的目录文件名,使用 -C
(Comment)参数指定注释,更多的参数可以使用 --help
参数查看。
生成的公钥格式为 <protocol> <key-blob> <comment>
,其中注释项通常用来指代要登录的用户名。
有了密钥对后,可以使用 ssh-copy-id user@host
命令将自己的公钥上传至远程主机,远程主机会将用户的公钥,保存在登录后的用户主目录的 $HOME/.ssh/authorized_keys
文件中。实际上,ssh-copy-id
命令的整个过程就如下命令一样:
1 | ssh user@host 'mkdir -p .ssh && cat >> .ssh/authorized_keys' < ~/.ssh/id_rsa.pub |
实际上,ssh-copy-id
还会对创建的文件及文件夹进行相关的权限设置,这里不过多介绍。
最后还要对远程主机的 SSH 服务端配置文件,即 /etc/ssh/sshd_config
文件进行相关配置,并重启 SSH 服务即可生效。具体而言,涉及到的配置项如下:
1 | RSAAuthentication yes |
紧接着使用 service sshd restart
重启 SSH 服务。
快速登录
$HOME/.ssh
目录下的 config
文件可配置快速登录选项,若没有,可以新建一个,具体而言,如下:
1 | host aliyun |
这代表当输入 ssh aliyun
时,其默认执行 ssh howie@192.168.0.41 -p 22 -i ~/.ssh/id_rsa
。当有多个别名需要设置时,其中间要空上一行。
常见问题
使用密钥连接后仍然需要输入登录密码:
这种情况一般是由于密钥登录失败所导致的,请检查 $HOME/.ssh
目录是否为 700 权限,$HOME/.ssh/authorized_keys
文件是否为 600 权限,除此之外的其他权限均不能成功。