SSH 协议详解(一):协议架构、传输层与用户认证
SSH,说白了就是远程控制的“安全隧道”。我早年做网络运维时,机房里的设备全靠 Telnet 管理,密码明文在网络上跑,抓个包就能看到。后来客户审计发现这个问题,差点丢了合同。从那以后,我所有远程管理场景全部强制上 SSH。
这一章,我们拆开 SSH 看看它到底怎么工作的。我会从协议架构讲起,再深入传输层和用户认证机制。你理解透了,以后配置调优、排错都能快人一步。
1. SSH 协议架构:三层模型
SSH 不是一个大块头,它分了三层。每层各司其职,有点像 OSI 模型的味道。
| 层次 | 作用 | 典型协议/组件 |
|---|---|---|
| 传输层协议 | 建立加密连接、服务器身份验证、密钥交换 | SSH-TRANS |
| 用户认证协议 | 验证客户端用户的身份 | SSH-USERAUTH |
| 连接协议 | 多路复用、通道管理、会话控制 | SSH-CONNECT |
我习惯把这三层比作“建路 → 验票 → 跑车”。传输层先把路修好,加密隧道建起来;用户认证层验你的票,看你有没有权限上车;连接层才是真正跑业务数据的地方。
核心要点:SSH 的认证和加密是分开的。传输层负责加密,用户认证层负责身份校验。两者解耦,你才能灵活选择认证方式。
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。
流程大致是:
- 服务器生成 DH 参数,签名后发给客户端
- 客户端验证签名,确认服务器身份
- 双方各自计算共享密钥 K
- 用 K 派生加密密钥、MAC 密钥、IV
- 交换结束,后续通信全部加密
嗯,这里要注意:服务器签名用的是主机密钥。主机密钥在 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 认证方式。原理是非对称加密:客户端持有私钥,服务器存公钥。
认证流程:
- 客户端发起认证请求,声明使用公钥方式
- 服务器检查
~/.ssh/authorized_keys里是否有该公钥 - 服务器生成随机数,用公钥加密后发给客户端
- 客户端用私钥解密,再计算签名发回
- 服务器验证签名,通过则认证成功
生成密钥对:
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 的三层架构把加密和认证分开了,设计得很干净。传输层负责建隧道、协商算法、交换密钥;用户认证层负责验明正身。密码认证简单但脆弱,公钥认证是主流,证书认证适合大规模管理。