SSH(Secure Shell)安全外壳协议详解
目录
- [一、SSH 协议基础认知](#一、SSH 协议基础认知)
- [二、SSH vs Telnet:为什么必须用 SSH](#二、SSH vs Telnet:为什么必须用 SSH)
- [三、SSH 协议版本与结构](#三、SSH 协议版本与结构)
- 四、密码学基础:对称与非对称加密
- [五、SSH 连接建立流程(完整握手)](#五、SSH 连接建立流程(完整握手))
- 六、身份验证方式
- [七、Known_Hosts 安全机制](#七、Known_Hosts 安全机制)
- 八、端口转发与隧道
- [九、SSH 常用命令与实战](#九、SSH 常用命令与实战)
- [十、SSH 安全加固建议](#十、SSH 安全加固建议)
一、SSH 协议基础认知
1.1 什么是 SSH 协议
SSH(Secure Shell) 是一种建立在 应用层 的安全加密网络协议,默认运行于 TCP 22 端口,主要用于:
| 核心功能 | 说明 |
|---|---|
| 远程登录 | 替代 Telnet,安全登录远程服务器 |
| 远程执行命令 | 在服务端执行命令、脚本 |
| 安全文件传输 | SFTP、SCP 安全拷贝文件 |
| 端口转发 | 建立加密隧道,代理流量 |
| X11 转发 | 图形界面远程显示 |
一句话总结 :SSH = 加密的远程终端协议,是 Linux/Unix 服务器管理的标准入口。
1.2 SSH 核心参数速查
协议版本 :SSH-2(主流,目前最安全)
默认端口 :22(可在 /etc/ssh/sshd_config 中修改)
传输层加密 :AES、ChaCha20-Poly1305、3DES 等
密钥交换 :Diffie-Hellman(DH)、ECDH
主机认证 :RSA/DSA/ECDSA/Ed25519 公钥签名
用户认证 :密码 / 公钥 / 键盘交互 / GSSAPI
1.3 SSH 协议族成员
SSH 协议并非单一协议,而是一组协议的组合:
┌─────────────────────────────────────────┐
│ SSH 协议体系 │
├──────────────┬──────────────────────────┤
│ 协议层 │ 包含子协议 │
├──────────────┼──────────────────────────┤
│ 应用层 │ SSH-CONNECT(连接管理) │
│ │ SSH-USERAUTH(用户认证) │
├──────────────┼──────────────────────────┤
│ 传输层 │ SSH-TRANS(加密传输) │
│ │ SSH-KEX(密钥交换) │
├──────────────┼──────────────────────────┤
│ 连接层 │ 频道(Channel)复用 │
│ │ X11转发、端口转发等 │
└──────────────┴──────────────────────────┘
二、SSH vs Telnet:为什么必须用 SSH
| 对比项 | Telnet | SSH |
|---|---|---|
| 传输方式 | 明文 | 全程加密 |
| 端口 | 23 | 22 |
| 身份验证 | 明文密码 | 加密认证 |
| 数据完整性 | ❌ 无 | ✅ HMAC校验 |
| 机密性 | ❌ 无 | ✅ AES等加密 |
| 典型用途 | 实验室/教学 | 生产环境必备 |
⚠️ 安全警示:使用 Telnet 远程管理 = 在公网上"裸奔",账号密码可被任何抓包工具直接获取。
三、SSH 协议版本与结构
3.1 SSH-1 vs SSH-2(必须掌握!)
SSH 发展至今主要有两个主版本:
SSH-1(1995年) SSH-2(2006年RFC 4250-4256)⭐主流
─────────────────────────────────────────────────────
• 仅支持 RSA 密钥 • 支持 RSA、DSA、ECDSA、Ed25519
• 存在已知安全漏洞 • 更强的密钥交换算法(ECDH)
• 已淘汰,不推荐使用 • 支持多信道复用(一个连接多会话)
• 传输层完整性校验 • 交换式加密,无后门风险
• 性能较低 • 性能更好,扩展性强
✅ 实战建议 :生产环境必须使用 SSH-2 ,确认配置文件中
Protocol 2。
3.2 SSH 数据包结构
SSH 传输层以数据包为单位进行通信,每个包结构如下:
┌──────────┬──────────┬────────────┬────────────┐
│ 包长度 │ 填充长度 │ 载荷 │ 填充数据 │ 消息认证码
│ (4字节) │ (1字节) │ (可变) │ (可变) │ (可选MAC)
└──────────┴──────────┴────────────┴────────────┘
↑ ↑
未加密区域 已加密区域
四、密码学基础:对称与非对称加密
4.1 核心概念速览
┌─────────────┐ ┌─────────────┐
│ 对称加密 │ │ 非对称加密 │
│ (一把钥匙) │ │ (两把钥匙) │
├─────────────┤ ├─────────────┤
│ 加密 = 解密 │ │ 公钥加密 │
│ 用同一把钥匙 │ │ 私钥解密 │
│ │ │ 或反之 │
└─────────────┘ └─────────────┘
4.2 对称加密(Symmetric Encryption)
原理 :加密和解密使用同一把密钥。
明文 ──────[加密算法 + 密钥]──────▶ 密文
密文 ──────[解密算法 + 密钥]──────▶ 明文
↑ 同一把密钥
常见算法:
| 算法 | 说明 | 密钥长度 |
|---|---|---|
| AES | SSH 主流推荐,高效安全 | 128/192/256位 |
| ChaCha20-Poly1305 | OpenSSH 8.2+ 默认,流加密 | 256位 |
| 3DES | 老旧,性能差,不推荐 | 168位 |
| DES | 已淘汰,易被破解 | 56位 |
优点 :✅ 加密解密速度快,适合大量数据传输
缺点:❌ 密钥分发困难 --- 如果密钥传输途中被截获,加密形同虚设
4.3 非对称加密(Asymmetric Encryption)
原理 :使用一对密钥,公钥加密的数据只有私钥能解密。
明文 ──────[公钥加密]──────▶ 密文 ──────[私钥解密]──────▶ 明文
↓ ↑
公钥(可公开) 私钥(必须保密)
常见算法:
| 算法 | 说明 | 应用场景 |
|---|---|---|
| RSA | 最经典,应用最广 | SSH 密钥、SSL证书 |
| ECDSA | 椭圆曲线,相同安全级别下密钥更短 | 现代SSH推荐 |
| Ed25519 | 最新一代,速度最快,安全最强 | OpenSSH 7.0+ 推荐 |
| Diffie-Hellman | 不用于加密解密,专门用于密钥交换 | SSH 密钥交换 |
优点 :✅ 解决密钥分发问题,公钥可自由传播
缺点:❌ 加密解密速度比对称加密慢 100-1000 倍
4.4 两者在 SSH 中的分工
SSH 的精妙设计 :非对称加密解决密钥分发难题,对称加密负责实际数据传输,各取所长!
第一阶段:密钥交换(非对称加密)
┌───────────────────────────────────┐
│ 客户端 ←──── 交换密钥 ────→ 服务端 │
└───────────────────────────────────┘
↓ 生成会话密钥
第二阶段:数据传输(对称加密)
┌───────────────────────────────────┐
│ 客户端 ←──[会话密钥加密]──→ 服务端 │
└───────────────────────────────────┘
五、SSH 连接建立流程(完整握手)
5.1 整体流程图
客户端 服务端
│ │
│ ① 版本协商(SSH-2.0) │
│──────────────────▶ SSH-2.0 ──────────────▶│
│◀──────────────────────────────────────────│
│ │
│ ② 算法协商(密钥交换算法、对称加密、MAC算法)│
│──────────────── SSH_MSG_KEXINIT ──────────▶│
│◀─────────────── SSH_MSG_KEXINIT ──────────│
│ │
│ ③ Diffie-Hellman 密钥交换 │
│ 生成会话密钥(对称密钥) │
│─────────── 客户端DH公钥 ──────────────────▶│
│◀─────────── 服务端DH公钥 ──────────────────│
│ 双方各自计算出会话密钥 │
│ │
│ ④ 服务端主机密钥认证 │
│◀───── SSH_MSG_KEXDH_REPLY(含服务端签名)──│
│ 客户端用 known_hosts 验证服务端身份 │
│ │
│ ⑤ 加密通信建立 │
│ 使用会话密钥开始加密传输 │
│ │
│ ⑥ 用户身份认证(密码/公钥) │
│══════════ 认证请求 =====================══►│
│ │
│ ⑦ 连接成功!打开 Shell / 执行命令 │
│═══════════════════════════════════════════►│
5.2 分步详解
步骤一:版本协商
客户端 ────────────────────────────────────▶ 服务端
"SSH-2.0-OpenSSH_8.9" ← "SSH-2.0-OpenSSH_8.9"
双方协商使用 SSH-2 协议(最高版本)
步骤二:算法协商
客户端和服务端各自列出支持的算法列表,取交集:
支持的算法(客户端): 支持的算法(服务端):
KEX算法: ecdh-sha2-nistp256, ecdh-sha2-nistp256,
diffie-hellman-group14 diffie-hellman-group14,
diffie-hellman-group1 curve25519-sha256
加密算法: aes256-ctr, aes192-ctr, aes256-gcm@openssh.com,
aes128-gcm@openssh.com chacha20-poly1305@openssh.com
MAC算法: hmac-sha2-256, hmac-sha2-512,
hmac-sha2-512 hmac-sha1
公钥算法: rsa-sha2-512, ecdsa-sha2-256, rsa-sha2-512,
ssh-ed25519 ssh-ed25519
协商结果:使用双方都支持的最优算法组合
步骤三:Diffie-Hellman 密钥交换(重点!)
DH 算法让双方在不传输密钥的情况下,共同生成相同的会话密钥:
原理示意(数学本质):
服务端选取大素数 p 和原根 g,公开发送
客户端随机生成私有数 a,计算 A = g^a mod p,发送给服务端
服务端随机生成私有数 b,计算 B = g^b mod p,发送给客户端
服务端计算:K = B^a mod p
客户端计算:K = A^b mod p
数学保证:双方计算的 K 完全相同!
第三方即使截获了 p, g, A, B,
也无法在合理时间内推算出 K(离散对数难题)
核心思想:密钥从不被传输,传输的只是用于计算密钥的"原材料"。
步骤四:会话密钥生成
密钥交换完成后,双方各自从 DH 共享密钥 K 派生出三个会话密钥:
| 密钥 | 用途 | 方向 |
|---|---|---|
IV_CLIENT_TO_SERVER |
客户端→服务端传输加密 | 单向 |
IV_SERVER_TO_CLIENT |
服务端→客户端传输加密 | 单向 |
ENCRYPTION_KEY |
数据流加密(分两个方向) | 双向独立 |
MAC_KEY |
数据完整性校验 | 双向独立 |
✅ 安全设计:即使一个方向的密钥被破解,另一个方向仍然安全。
六、身份验证方式
SSH 支持多种用户认证方式,按安全性从低到高排序:
6.1 密码认证(Password Authentication)
流程:
① 用户输入用户名 + 密码
② 客户端将密码加密后发送到服务端
③ 服务端验证后返回结果
优点:简单易用,无需额外配置
缺点:❌ 密码易被钓鱼、暴力破解、撞库攻击
⚠️ 密码认证虽然经过加密传输,但安全性较低,建议配合强密码策略。
6.2 公钥认证(Public Key Authentication)⭐推荐
这是 SSH 最安全、最推荐的认证方式:
核心原理:
┌──────────────────────────────────────────┐
│ 用户主机(客户端) │
│ 密钥对:id_rsa(私钥) / id_rsa.pub(公钥│
│ ↓ 手动或 ssh-copy-id 传输公钥 │
│ 服务端 ~/.ssh/authorized_keys │
└──────────────────────────────────────────┘
认证流程:
① 客户端声明:"我想用我的公钥登录"
② 服务端生成随机挑战(Challenge),用客户端公钥加密后发送
③ 客户端用私钥解密挑战,得到原文
④ 客户端将解密结果用会话密钥加密返回
⑤ 服务端验证通过 → 允许登录
✅ 优势:私钥永不传输,难以被截获;可设置 passphrase 二次保护;支持自动化脚本。
6.3 密钥生成与部署实战
bash
# 1. 生成密钥对(推荐 Ed25519,性能最强)
ssh-keygen -t ed25519 -C "your_email@example.com"
# 或生成 RSA 密钥
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
# 2. 一键复制公钥到目标服务器
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@192.168.1.100
# 3. 之后连接无需输入密码(仅首次需输入 passphrase)
ssh user@192.168.1.100
6.4 其他认证方式
| 方式 | 说明 |
|---|---|
| 键盘交互认证 | 服务端向用户发送问题(动态密码、OTP 等) |
| GSSAPI 认证 | 结合 Kerberos/LDAP 企业认证体系 |
| 主机认证 | 机器之间的互信认证 |
七、Known_Hosts 安全机制
7.1 机制原理
客户端首次连接陌生 SSH 服务器时,会将服务端的主机公钥指纹 记录到 ~/.ssh/known_hosts 文件:
bash
# 文件格式(每行一条记录)
# 主机名/IP 密钥类型 公钥指纹
192.168.1.100 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...
server.example.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQAB...
7.2 信任判断流程
首次连接新服务器:
┌────────────────────────────────────────────┐
│ ⚠️ 警告:无法确认主机 "192.168.1.100" │
│ 的真实性,其公钥指纹为: │
│ SHA256:xxxxxxxxxxxxxxxxxxx │
│ │
│ 您确定想要继续连接吗?(yes/no) │
└────────────────────────────────────────────┘
↓ 用户输入 yes
公钥记录到 known_hosts,下次连接自动信任
再次连接:
读取 known_hosts 中的公钥
↓
对比服务端发来的公钥
↓
✅ 匹配 → 安全连接
❌ 不匹配 → ⚠️ 警告"可能遭到中间人攻击"
7.3 主机密钥文件位置
bash
# 服务端主机密钥存放位置(/etc/ssh/)
/etc/ssh/ssh_host_rsa_key # RSA 主机私钥
/etc/ssh/ssh_host_rsa_key.pub # RSA 主机公钥
/etc/ssh/ssh_host_ecdsa_key # ECDSA 主机私钥
/etc/ssh/ssh_host_ed25519_key # Ed25519 主机私钥
# 客户端信任存储
~/.ssh/known_hosts
~/.ssh/known_hosts2 # SSH-1 遗留
7.4 公钥变化时的处理(重要!)
⚠️ 如果已知主机公钥发生变化,务必警惕!可能存在中间人攻击。
正当变化的场景(可确认后重新信任):
- 服务器重装了操作系统
- 服务器重新生成了 SSH 主机密钥
- 服务器 IP 地址被复用
bash
# 解决方案:删除旧记录,重新建立信任
# 方法1:直接编辑文件(推荐知道具体行号时)
vim ~/.ssh/known_hosts
# 删除对应行后保存
# 方法2:使用 ssh-keygen 自动删除
ssh-keygen -R 192.168.1.100
# 方法3:清空所有记录(慎用!)
echo "" > ~/.ssh/known_hosts
# 验证新指纹(通过其他安全渠道,如电话询问管理员)
ssh-keyscan -H 192.168.1.100
八、端口转发与隧道
8.1 本地端口转发(Local Port Forwarding)
将远程服务器的端口,通过 SSH 隧道映射到本地:
bash
# 将远程服务器的 3306(MySQL)映射到本地 3333
ssh -L 3333:localhost:3306 user@remote-server
# 原理:
# 本地应用 ──▶ localhost:3333 ──▶ [SSH加密隧道] ──▶ 远程服务器的 localhost:3306
┌─────────┐ ┌──────────┐ ┌──────────┐
│ MySQL │ │ SSH隧道 │ │ 远程服务 │
│ 客户端 │──:3333──▶│ 加密转发 │─────────▶ │ MySQL │
│ │ │ │ │ :3306 │
└─────────┘ └──────────┘ └──────────┘
8.2 远程端口转发(Remote Port Forwarding)
从远程服务器反向映射本地端口(用于内网穿透):
bash
# 将本地 8080 暴露给远程服务器的 9090
ssh -R 9090:localhost:8080 user@remote-server
# 常用场景:让外网服务器访问内网开发机
8.3 动态端口转发(SOCKS 代理)
bash
# 将本地 1080 作为 SOCKS5 代理
ssh -D 1080 user@remote-server
# 配置浏览器或应用使用 localhost:1080 代理
# 所有流量通过远程服务器转发
8.4 端口转发对比
| 类型 | 参数 | 方向 | 典型场景 |
|---|---|---|---|
| 本地转发 | -L |
本地→远程 | 访问远程内网数据库 |
| 远程转发 | -R |
远程→本地 | 内网穿透,暴露本地服务 |
| 动态转发 | -D |
本地SOCKS | 加密浏览,绕过限制 |
九、SSH 常用命令与实战
9.1 基础连接
bash
# 标准连接
ssh user@hostname
# 指定端口(服务器改了默认端口时)
ssh -p 2222 user@hostname
# 指定密钥文件(不用默认密钥时)
ssh -i ~/.ssh/my_key.pem user@hostname
# 登录后直接执行命令(不打开交互式shell)
ssh user@hostname "ls -la /var/log"
9.2 文件传输
bash
# SCP(安全复制)
# 上传到服务器
scp ./localfile.txt user@hostname:/remote/path/
# 从服务器下载
scp user@hostname:/remote/file.txt ./local/path/
# 递归上传整个目录
scp -r ./local_folder user@hostname:/remote/path/
# 指定端口
scp -P 2222 localfile.txt user@hostname:/path/
# SFTP(交互式传输,类似FTP)
sftp user@hostname
sftp> ls # 列出远程目录
sftp> get file.txt # 下载文件
sftp> put file.txt # 上传文件
9.3 SSH 配置优化
bash
# ~/.ssh/config 示例(简化日常连接)
Host alias-name
HostName 192.168.1.100
User root
Port 22
IdentityFile ~/.ssh/id_ed25519
ForwardAgent yes
ServerAliveInterval 60 # 防止断线(每60秒发心跳)
ServerAliveCountMax 3
Host alias2
HostName server2.example.com
User admin
Port 2222
IdentityFile ~/.ssh/work_key
# 配置后直接使用别名连接
ssh alias-name
9.4 免密码登录配置清单
✅ 一、检查客户端密钥是否存在
ls ~/.ssh/id_ed25519.pub
✅ 二、生成密钥(如不存在)
ssh-keygen -t ed25519 -C "描述"
✅ 三、复制公钥到服务器
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@hostname
✅ 四、配置 SSH config(可选,更方便)
✅ 五、测试连接
ssh user@hostname
# 成功:直接登录,无需密码
十、SSH 安全加固建议
10.1 服务器端配置(/etc/ssh/sshd_config)
conf
# 协议版本(必须SSH-2)
Protocol 2
# 更改默认端口(22→高位端口,减少扫描)
Port 2222
# 禁止ROOT直接登录
PermitRootLogin no
# 禁止使用空密码
PermitEmptyPasswords no
# 限制用户登录(仅允许指定用户)
AllowUsers admin deploy@192.168.1.0/24
# 公钥认证(开启)
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
# 密码认证(建议关闭,仅保留公钥)
PasswordAuthentication no
# X11转发(按需开启)
X11Forwarding no
# 最大连接数
MaxSessions 10
# 空闲超时断开(5分钟无操作自动断开)
ClientAliveInterval 300
ClientAliveCountMax 2
# 禁用某些弱算法
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
KexAlgorithms curve25519-sha256,ecdh-sha2-nistp521
10.2 安全加固检查清单
🔒 账户安全
□ 禁用 ROOT 登录
□ 使用强密码或禁用密码登录
□ 定期更换密钥
🔒 访问控制
□ 修改默认端口 22
□ 使用 IP 白名单(防火墙 / AllowUsers)
□ 限制登录失败次数(fail2ban)
🔒 密钥管理
□ 使用 Ed25519 或 RSA 4096 位密钥
□ 私钥设置 passphrase
□ 定期轮换密钥
□ 禁止私钥泄露(不提交到 Git)
🔒 监控审计
□ 开启 SSH 日志审计
□ 监控异常登录(失败登录告警)
□ 定期检查 authorized_keys
10.3 常见攻击与防御
| 攻击类型 | 原理 | 防御手段 |
|---|---|---|
| 暴力破解 | 不断尝试账号密码 | 禁用密码+公钥认证;fail2ban |
| 中间人攻击 | 伪装成目标服务器 | 检查 known_hosts;HPKP |
| SSH 隧道滥用 | 加密隧道绕过防火墙 | 限制端口转发;审计日志 |
| 弱密钥攻击 | 使用 1024 位以下 RSA | 使用 Ed25519 / RSA 4096 |
| 私钥泄露 | 密钥文件被窃取 | passphrase;权限 600;定期轮换 |
知识总结
┌──────────────────────────────────────────────────────┐
│ SSH 协议全景图 │
├──────────────────────────────────────────────────────┤
│ │
│ 连接建立阶段 │
│ 版本协商 → 算法协商 → DH密钥交换 → 主机认证 │
│ ↓ │
│ 生成会话密钥(三层密钥体系) │
│ ↓ │
│ 身份验证阶段 │
│ 公钥认证 / 密码认证 / 键盘交互 │
│ ↓ │
│ 加密通信阶段 │
│ 对称加密传输数据 / HMAC完整性校验 │
│ │
└──────────────────────────────────────────────────────┘
学习提示:理解 SSH 协议的关键在于抓住两条主线:
- 密钥交换:DH 算法如何让双方"隔空"生成相同的会话密钥
- 分层安全:非对称加密保护密钥交换,对称加密保护数据传输