SSH概要
Secure Shell,安全外壳协议,简称ssh,是一种建立在应用层基础上的安全协议,通过对密码进行加密传输验证,可在不安全的网络中对网络服务提供安全的传输环境,实现ssh客户端和ssh服务器端的连接
(1).SSH是传输层和应用层上的安全协议,它只能通过加密连接双方会话的方式来保证连接的安全性。当使用ssh连接成功后,将建立客户端和服务端之间的会话,该会话是被加密的,之后客户端和服务端的通信都将通过会话传输。
(2).SSH服务的守护进程为sshd,默认监听在22端口上。
(3).所有ssh客户端工具,包括ssh命令,scp,sftp,ssh-copy-id等命令都是借助于ssh连接来完成任务的。也就是说它们都连接服务端的22端口,只不过连接上之后将待执行的相关命令转换传送到远程主机上,由远程主机执行。
(4).ssh客户端命令(ssh、scp、sftp等)读取两个配置文件:全局配置文件/etc/ssh/ssh_config和用户配置文件~/.ssh/config。实际上命令行上也可以传递配置选项。它们生效的优先级是:命令行配置选项 > ~/.ssh/config > /etc/ssh/ssh_config。
(5).ssh涉及到两个验证:主机验证和用户身份验证。通过主机验证,再通过该主机上的用户验证,就能唯一确定该用户的身份。一个主机上可以有很多用户,所以每台主机的验证只需一次,但主机上每个用户都需要单独进行用户验证。
(6).ssh支持多种身份验证,最常用的是密码验证机制和公钥认证机制,其中公钥认证机制在某些场景实现双机互信时几乎是必须的。虽然常用上述两种认证机制,但认证时的顺序默认是gssapi-with-mic,hostbased,publickey,keyboard-interactive,password。注意其中的主机认证机制hostbased不是主机验证,由于主机认证用的非常少(它所读取的认证文件为/etc/hosts.equiv或/etc/shosts.equiv),所以网络上比较少见到它的相关介绍。总的来说,通过在ssh配置文件(注意不是sshd配置文件)中使用指令PreferredAuthentications改变认证顺序不失为一种验证的效率提升方式。
(7).ssh客户端其实有不少很强大的功能,如端口转发(隧道模式)、代理认证、连接共享(连接复用)等。
(8).ssh服务端配置文件为/etc/ssh/sshd_config,注意和客户端的全局配置文件/etc/ssh/ssh_config区分开来。
(9).很重要却几乎被人忽略的一点,ssh登录时会请求分配一个伪终端。但有些身份认证程序如sudo可以禁止这种类型的终端分配,导致ssh连接失败。例如使用ssh执行sudo命令时sudo就会验证是否要分配终端给ssh
SSH认证过程分析
假如从客户端A连接到服务端B上,将包括主机验证和用户身份验证两个过程,以RSA非对称加密算法为例。
主机验证过程(发生在客户端)
当客户端A要连接服务端B时,首先将进行主机验证过程,即客户端A判断是否曾经连接过主机B。
客户端A执行ssh
命令连接时, 会接收到服务端B的ssh公钥, 也可以称作B机器的主机信息(即host key,表示主机身份标识)
服务端B的公钥信息保存在/etc/ssh/ssh_host*
文件中, 其中的*表示不同的加密算法, ssh服务启动时会选择一种算法的.pub
文件作为公钥
在本例中选择的是ECDSA
算法, ssh_host_ecdsa_key.pub
文件内容为:
ecdsa-sha2-nistp256 AAAAE...vC2PDRA08c7c= root@iZuf60sq23qlao62jmsy0zZ
通过空格分隔为三个部分:
- 第一部分表示服务端B的公钥加密算法
- 第二部分表示服务端B的公钥值
- 第三部分表示服务端B的公钥生成时的用户信息
第一次建立连接
若客户端A从未连接过服务端B(即第一次建立连接), 则会询问是否进行连接
图中展示了两个信息:
- 服务端B的公钥是通过
ECDSA
算法进行加密的 - 由于公钥长度太长, 这里对公钥再次进行了加密, 得出公钥的指纹, 即
SHA256
后面的44位字符串
输入yes
则会继续连接, 并将B的公钥信息保存至客户端A的~/.ssh/known_hosts
文件中, 如:
|1|xNN...6aRA= ecdsa-sha2-nistp256 AAAAE...vC2PDRA08c7c=
每行数据表示一个主机信息, 通过空格分隔为三个部分:
- 第一部分表示服务端B的ip相关信息
- 第二部分表示服务端B的公钥加密算法
- 第三部分表示服务端B的公钥值
其中第2、3两个部分的值和服务端B的公钥文件``ssh_host_ecdsa_key.pub`中的值相同。
后续连接
后面再进行连接时, 则会将服务端B发送过来的公钥信息(host key)和~/.ssh/known_hosts
文件中保存的host key进行比较.
若两者相同, 则验证通过, 进行下一个过程--身份验证
若不相同, 则提示主机认证失败, 如:
上述报错意思为本次接收的指纹wtCqN4lUaPNJb1TNuLawnI1JegJ3xGrda5yij+bo0g8
和~/.ssh/known_hosts
文件中保存的host key指纹不一致, 可以使用ssh-keygen -f "/home/alex/.ssh/known_hosts" -R "[127.0.0.1]:2222"
命令删除原文件中保存的host key信息. 删除后再连接, 则又会回到第一次建立连接时的流程
host key指纹
ssh并非直接比对host key,因为host key太长了,比对效率较低。所以ssh将host key转换成host key指纹,然后比对两边的host key指纹即可。host key的指纹可由ssh-kegen
命令计算得出。
计算服务端B的host key指纹
(base) alex@Aliyun-ALex:~$ sudo ssh-keygen -l -f /etc/ssh/ssh_host_ecdsa_key
256 SHA256:N2QawIygnLo3m34fDevSECWNK1S7Ow+54wXnHQwMwko root@iZuf60sq23qlao62jmsy0zZ (ECDSA)
计算客户端A中known_hosts
文件保存的B的host key
指纹, 两者相同
alex@LPT006526:~$ ssh-keygen -l -f ~/.ssh/known_hosts
256 SHA256:N2QawIygnLo3m34fDevSECWNK1S7Ow+54wXnHQwMwko |1|xNNGD5QK4PWE8ecSJ1aWhdu6gVw=|T13/F6JZiCNy7L7eQVuIAib6aRA= (ECDSA)
身份验证过程
主机验证通过后,将进入身份验证阶段。SSH支持多种身份验证机制,它们的验证顺序如下:gssapi-with-mic,hostbased,publickey,keyboard-interactive,password,但常见的是密码认证机制(password)和公钥认证机制(public key)。当公钥认证机制未通过时,再进行密码认证机制的验证。
在进行上一步的主机验证时, 客户端A已经得到了服务端B的公钥
密码认证
密码认证过程
-
客户端A将用户输入的密码使用服务端B的公钥进行加密, 将加密结果发送给服务端B
-
服务端B使用自己的私钥对加密结果进行解密, 得到密码, 与本地密码文件进行比较, 若相同则认证成功, 否则失败
公钥认证
公钥认证前提
公钥认证可以不用输入密码, 但有两个前提:
-
客户端A也生成一套非对称秘钥, 可以使用
ssh-keygen
命令生成, 默认情况下会在~/.ssh/
目录下生成id_rsa
(私钥)和id_rsa.pub
(公钥)文件alex@LPT006526:~$ ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/home/alex/.ssh/id_rsa): # 直接回车,使用默认值 Enter passphrase (empty for no passphrase): # 直接回车,不设置密码 Enter same passphrase again: # 直接回车,不设置密码 Your identification has been saved in /home/alex/.ssh/id_rsa. # 私钥 Your public key has been saved in /home/alex/.ssh/id_rsa.pub. # 公钥 The key fingerprint is: SHA256:zQtCAGgFVR0Ia89w9D0i0VJMZeAu94XEdbjYTlpuWrM alex@LPT006526 # 公钥指纹 The key's randomart image is: # 公钥图片码 +---[RSA 2048]----+ | o==++B=+o ... | |.. o++++ ... | |. + oo+ =o . | | . =.o o+o= | | +.oS.O. | | o..o.B | | .= o | | . E | | | +----[SHA256]-----+
-
将客户端A的公钥放在服务端B的
~/.ssh/authorized_keys
文件中, 可以在客户端A中使用命令ssh-copy-id
进行设置, 也可以手动将客户端A的公钥文件~/.ssh/id_rsa.pub
中的值追加到服务端B的~/.ssh/authorized_keys
文件中alex@LPT006526:~$ ssh-copy-id [email protected] /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/alex/.ssh/id_rsa.pub" /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys [email protected]'s password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh '[email protected]'" and check to make sure that only the key(s) you wanted were added.
以上两个前提设置完成后, 在客户端A中直接输入ssh连接命令即可连接至服务端B中, 不需要输入密码
公钥认证的过程
- 客户端A发送A的公钥给服务端B
- 服务端B接收到A的公钥后, 去
~/.ssh/authorized_keys
文件中查找是否存在A的公钥, 若存在, 则用此公钥加密一个随机字符串, 并返回给客户端A - 客户端A收到后使用自己的私钥进行解密, 并将解密结果发送给服务端B
- 服务端B收到A的解密结果后与之前的随机字符串进行比较, 若相同, 则认证成功. 否则认证失败
MFA
多重要素验证(英语:Multi-factor authentication,缩写为 MFA),又译多因子认证、多因素验证、多因素认证,是一种计算机访问控制的方法,用户要通过两种以上的认证机制之后,才能得到授权,使用计算机资源。
相比仅凭账号密码,MFA提供了更加安全的资源保护。下面列举一些MFA的例子:
- 用户安全问题
- 密码
- OTPs
- 软件安全码、keys
- 指纹、人脸识别、声纹及其他生物特征
- 用户行为足迹分析
OTP
OTP(One-Time-Password)是MFA(Multi-Factor-Authentication)的一个实现模型. 顾名思义,一次性密码。如短信验证码, 谷歌认证等
HOTP
HOTP中,H指代 Hash-based Message Authentication Code,另一种不那么专业的解释方法为:HOTP是一种事件驱动的OTP,它的moving factor基于一个计数器。
HOTP每一次请求,都会让计数器递增,而生成的OTP在下一次计数前保持有效。OTP生成器和服务器会同步监测到用户的有效访问行为。HOTP的一个例子为Yubikey。
TOTP
TOTP中,T指代Time-based,类似HOTP,但是它的moving factor基于时间。
TOTP的有效时间被称为timestep(时间步长),通常被设定为30、60秒,如果在这个时间窗口内没有验证此密码,则会失效。