SSH 工作原理与认证机制详解
SSH 协议基础概述
Secure Shell(SSH)是一种运行在应用层的安全网络协议,用于在不可信网络中安全地传输数据。它通过加密客户端与服务器之间的通信会话,确保远程登录、文件传输等操作的机密性和完整性。
- SSH 属于应用层协议,但其加密机制涉及传输层安全。一旦连接建立,所有通信均在加密通道中进行。
- SSH 服务由守护进程
sshd提供,默认监听 TCP 22 端口。 - 常见的 SSH 工具如
ssh、scp、sftp和ssh-copy-id都基于 SSH 协议实现功能,本质是通过加密连接执行远程命令或传输数据。 - SSH 客户端读取两个配置文件:系统级配置
/etc/ssh/ssh_config和用户级配置~/.ssh/config。若命令行指定参数,则优先级为:命令行选项 > 用户配置 > 系统配置。 - 连接过程中包含两类验证:主机身份验证和用户身份验证。前者确认目标服务器的身份,后者确认登录用户的合法性。每个主机只需完成一次主机验证,而每位用户需独立完成身份认证。
- 支持多种认证方式,默认尝试顺序为:
gssapi-with-mic、hostbased、publickey、keyboard-interactive、password。最常用的是公钥认证和密码认证。可通过配置文件中的PreferredAuthentications指令调整顺序以提升效率。 - 客户端具备高级特性,包括端口转发(隧道)、代理跳转、连接复用等,适用于复杂网络环境下的安全访问。
- 服务端配置位于
/etc/ssh/sshd_config,与客户端配置文件名称不同,注意区分。 - SSH 登录通常请求分配伪终端(pseudo-TTY)。某些权限管理工具(如
sudo)可能限制 TTY 分配,导致无法正常连接,需在配置中允许相关行为。
主机身份验证流程
当客户端首次尝试连接服务器时,服务器会发送其主机公钥(host key),该密钥存储于 /etc/ssh/ssh_host_* 文件中,具体文件取决于启用的加密算法(如 RSA、ECDSA、Ed25519)。
例如,使用 ECDSA 算法时,公钥文件内容如下:
ecdsa-sha2-nistp256 AAAAE...vC2PDRA08c7c= root@server-hostname
该行分为三部分:
- 加密算法标识
- 公钥内容(Base64 编码)
- 生成时的用户和主机信息
首次连接处理
若客户端未记录该主机的公钥,将显示类似提示:
The authenticity of host 'example.com (192.168.1.10)' can't be established.
ECDSA key fingerprint is SHA256:N2QawIygnLo3m34fDevSECWNK1S7Ow+54wXnHQwMwko.
Are you sure you want to continue connecting (yes/no)?
输入 yes 后,客户端将服务器公钥保存至本地 ~/.ssh/known_hosts 文件,格式如下:
|1|xNNGD5QK4PWE8ecSJ1aWhdu6gVw=|T13/F6JZiCNy7L7eQVuIAib6aRA= ecdsa-sha2-nistp256 AAAAE...vC2PDRA08c7c=
其中第一段为哈希化的 IP 地址,用于防止 DNS 劫持攻击。
后续连接验证
再次连接时,客户端比对收到的主机公钥与其本地 known_hosts 中保存的信息。若匹配,则继续;若不一致,将触发警告:
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
此情况常见于服务器重装系统、更换密钥或中间人攻击。可通过以下命令清除旧记录:
ssh-keygen -f "~/.ssh/known_hosts" -R "hostname_or_ip"
之后重新连接即可恢复初始流程。
主机密钥指纹计算
由于原始公钥较长,不便人工比对,SSH 使用哈希算法生成"指纹"(fingerprint)进行快速验证。可使用 ssh-keygen -l 查看:
# 查看服务器本地 host key 指纹
sudo ssh-keygen -l -f /etc/ssh/ssh_host_ecdsa_key
# 输出:256 SHA256:N2QawIygnLo3m34fDevSECWNK1S7Ow+54wXnHQwMwko root@server-hostname (ECDSA)
# 查看 known_hosts 中对应条目的指纹
ssh-keygen -l -f ~/.ssh/known_hosts
# 输出应与上述一致
用户身份认证机制
主机验证通过后,进入用户身份认证阶段。主要方式包括密码认证和公钥认证。
密码认证流程
- 客户端获取服务器公钥(已在主机验证阶段完成)。
- 用户输入密码,客户端使用服务器公钥对其进行加密。
- 加密后的密码发送至服务器。
- 服务器使用自身私钥解密,并与系统中存储的密码哈希比对(实际不会明文比较),一致则认证成功。
公钥认证设置与流程
实现免密登录需满足两个条件:
- 生成客户端密钥对:使用
ssh-keygen命令生成私钥和公钥文件,默认路径为~/.ssh/id_rsa和~/.ssh/id_rsa.pub。 - 部署公钥到服务器:将客户端公钥内容添加至目标用户家目录下的
~/.ssh/authorized_keys文件中。可通过ssh-copy-id user@host自动完成。
示例操作:
alex@client:~$ ssh-keygen -t rsa -b 2048
# 直接回车接受默认设置
...
Your public key has been saved in /home/alex/.ssh/id_rsa.pub
alex@client:~$ ssh-copy-id alex@47.102.114.90
# 输入一次密码后完成公钥上传
Now try logging into the machine...
公钥认证交互过程
- 客户端向服务器声明将使用公钥认证,并发送自己的公钥。
- 服务器检查该公钥是否存在于
~/.ssh/authorized_keys中。 - 若存在,服务器生成一个随机字符串,用客户端的公钥加密后发送给客户端。
- 客户端使用本地私钥解密该字符串,并将结果返回服务器。
- 服务器比对返回值与原始字符串是否一致,若一致则认证通过。
此过程利用非对称加密特性,证明客户端持有对应的私钥,而无需传输私钥本身,安全性更高。
多因素认证(MFA)支持
为增强安全性,SSH 可结合多因素认证(Multi-Factor Authentication, MFA),要求用户提供两种及以上类型的凭证:
- 知识要素(What you know):如密码、安全问题
- 持有要素(What you have):如手机验证码、硬件令牌(YubiKey)
- 生物特征(What you are):如指纹、面部识别
- 行为模式:如登录时间、地理位置分析
一次性密码(OTP)机制
OTP 是 MFA 的一种实现形式,每次认证使用唯一且仅能使用一次的密码。
HOTP:基于事件的一次性密码
HMAC-based One-Time Password(HOTP)依赖计数器作为动态因子。每次成功验证后计数器递增,生成的密码在下次同步前有效。典型设备如 YubiKey 即采用此类机制。
TOTP:基于时间的一次性密码
Time-based One-Time Password(TOTP)使用当前时间戳作为动态因子,通常以 30 或 60 秒为时间步长(timestep)。在此窗口内生成的密码有效,过期后自动失效。Google Authenticator 和 Microsoft Authenticator 均基于 TOTP 标准。