SSH 协议详解(一):协议架构、传输层与用户认证

SSH,说白了就是远程控制的“安全隧道”。我早年做网络运维时,机房里的设备全靠 Telnet 管理,密码明文在网络上跑,抓个包就能看到。后来客户审计发现这个问题,差点丢了合同。从那以后,我所有远程管理场景全部强制上 SSH。

这一章,我们拆开 SSH 看看它到底怎么工作的。我会从协议架构讲起,再深入传输层和用户认证机制。你理解透了,以后配置调优、排错都能快人一步。

1. SSH 协议架构:三层模型

SSH 不是一个大块头,它分了三层。每层各司其职,有点像 OSI 模型的味道。

层次 作用 典型协议/组件
传输层协议 建立加密连接、服务器身份验证、密钥交换 SSH-TRANS
用户认证协议 验证客户端用户的身份 SSH-USERAUTH
连接协议 多路复用、通道管理、会话控制 SSH-CONNECT

我习惯把这三层比作“建路 → 验票 → 跑车”。传输层先把路修好,加密隧道建起来;用户认证层验你的票,看你有没有权限上车;连接层才是真正跑业务数据的地方。

核心要点:SSH 的认证和加密是分开的。传输层负责加密,用户认证层负责身份校验。两者解耦,你才能灵活选择认证方式。

SSH 协议三层架构 连接协议(SSH-CONNECT) 通道管理 · 会话复用 · 端口转发 · X11 转发 用户认证协议(SSH-USERAUTH) 密码认证 · 公钥认证 · 证书认证 · GSSAPI 传输层协议(SSH-TRANS) 密钥交换 · 加密算法协商 · 服务器主机密钥验证 自底向上构建

2. 传输层协议:加密隧道怎么建起来的?

传输层是 SSH 的基石。没有它,后面两层都是空谈。它的核心任务就三个:算法协商、密钥交换、服务器身份验证。

2.1 握手流程

客户端连上服务器 22 端口后,双方先交换版本号。比如:

客户端: SSH-2.0-OpenSSH_8.9p1
服务器: SSH-2.0-OpenSSH_8.9p1

版本号交换完,就开始协商算法。双方各自发一个自己支持的算法列表,然后取交集。我遇到过一个问题:客户端和服务器都支持某个算法,但顺序不同导致协商失败。后来发现是 OpenSSH 版本差异导致的兼容性 bug。

实战技巧:用 ssh -v 可以看到详细的协商过程。如果连不上,先加 -v 看输出,大部分问题都能定位。

2.2 密钥交换(KEX)

算法协商完,进入密钥交换阶段。经典的 Diffie-Hellman 密钥交换在这里登场。双方在不安全的网络上,共同算出一个共享密钥。这个密钥用来派生后续的加密密钥、MAC 密钥和 IV。

流程大致是:

  1. 服务器生成 DH 参数,签名后发给客户端
  2. 客户端验证签名,确认服务器身份
  3. 双方各自计算共享密钥 K
  4. 用 K 派生加密密钥、MAC 密钥、IV
  5. 交换结束,后续通信全部加密

嗯,这里要注意:服务器签名用的是主机密钥。主机密钥在 SSH 服务端首次启动时生成,保存在 /etc/ssh/ssh_host_* 文件里。客户端第一次连服务器时,会提示你确认主机密钥指纹。这就是防中间人攻击的第一道防线。

避坑指南:我曾经遇到客户重装系统后,SSH 客户端报“Host key verification failed”。原因是服务器主机密钥变了,客户端 known_hosts 里还存着旧的。解决方案:手动删除旧指纹,或者用 ssh-keygen -R hostname 清理。

2.3 加密算法与 MAC

SSH 支持多种对称加密算法。常见的有:

算法 密钥长度 模式 安全性
aes128-ctr 128 bit CTR 高
aes256-ctr 256 bit CTR 极高
chacha20-poly1305 256 bit AEAD 极高
aes128-cbc 128 bit CBC 中(已不推荐)

我个人习惯优先选 chacha20-poly1305 或 aes256-ctr。CBC 模式在 SSH 里有过漏洞(CVE-2008-5161),能避免就避免。

MAC(消息认证码)用来保证数据完整性。常用的是 hmac-sha2-256 和 hmac-sha2-512。老旧的 hmac-md5 就别用了。

3. 用户认证机制

传输层隧道建好了,接下来就是用户认证。SSH 支持多种认证方式,最常用的三种:密码、密钥、证书。

3.1 密码认证

最简单,也最容易被暴力破解。客户端把密码加密后发给服务器,服务器验证。

ssh user@host
user@host's password: ******

密码认证的缺点很明显:

  • 容易遭受暴力破解
  • 密码复杂度难以强制
  • 无法实现免密登录

建议:生产环境关闭密码认证,改用密钥或证书。在 /etc/ssh/sshd_config 里设置 PasswordAuthentication no。

3.2 公钥认证

这是目前最主流的 SSH 认证方式。原理是非对称加密:客户端持有私钥,服务器存公钥。

认证流程:

  1. 客户端发起认证请求,声明使用公钥方式
  2. 服务器检查 ~/.ssh/authorized_keys 里是否有该公钥
  3. 服务器生成随机数,用公钥加密后发给客户端
  4. 客户端用私钥解密,再计算签名发回
  5. 服务器验证签名,通过则认证成功

生成密钥对:

ssh-keygen -t ed25519 -C "your_email@example.com"

我个人强烈推荐使用 Ed25519 算法。它比 RSA 快,密钥短,安全性还高。RSA 4096 位当然也安全,但 Ed25519 性能更好。

关键点:私钥必须保护好。我见过有人把私钥放在共享目录里,结果被同事误删了。建议私钥设置密码保护(passphrase),用 ssh-agent 管理。

3.3 证书认证

公钥认证有个管理痛点:服务器多了,每台都要手动添加公钥。证书认证解决了这个问题。

SSH 证书不是 HTTPS 那种 X.509 证书,而是 OpenSSH 自有的证书格式。架构里有一个 CA(证书颁发机构),用 CA 私钥给用户公钥签名,生成证书。服务器信任 CA 的公钥,只要客户端出示的证书是 CA 签发的,就放行。

工作流程:

  • CA 生成自己的密钥对
  • 用户生成自己的密钥对,把公钥发给 CA
  • CA 用私钥对用户公钥签名,生成证书
  • 用户用证书 + 私钥登录
  • 服务器验证证书的 CA 签名

配置示例:

# 在服务器上配置信任的 CA 公钥
TrustedUserCAKeys /etc/ssh/ca_user_key.pub

# 用户证书登录
ssh -i ~/.ssh/id_ed25519-cert.pub user@host

避坑指南:我曾经帮一家公司部署 SSH 证书认证,结果证书有效期设了 10 年。后来发现证书过期后,所有运维人员都登不上服务器。教训:证书有效期要合理设置,并建立续期流程。

3.4 认证方式对比

特性 密码认证 公钥认证 证书认证
配置复杂度 低 中 高
安全性 低 高 高
管理成本 低 中(每台服务器都要加公钥) 低(集中管理)
适合场景 临时、测试环境 小规模运维 大规模、企业级

你想想看,如果管理 1000 台服务器,每台都要手动添加公钥,那得累死。证书认证一次签发,全局生效,这才是企业级的做法。

4. 本章小结

SSH 的三层架构把加密和认证分开了,设计得很干净。传输层负责建隧道、协商算法、交换密钥;用户认证层负责验明正身。密码认证简单但脆弱,公钥认证是主流,证书认证适合大规模管理。