SSH(Secure Shell)安全外壳协议详解

SSH(Secure Shell)安全外壳协议详解


目录

  1. [一、SSH 协议基础认知](#一、SSH 协议基础认知)
  2. [二、SSH vs Telnet:为什么必须用 SSH](#二、SSH vs Telnet:为什么必须用 SSH)
  3. [三、SSH 协议版本与结构](#三、SSH 协议版本与结构)
  4. 四、密码学基础:对称与非对称加密
  5. [五、SSH 连接建立流程(完整握手)](#五、SSH 连接建立流程(完整握手))
  6. 六、身份验证方式
  7. [七、Known_Hosts 安全机制](#七、Known_Hosts 安全机制)
  8. 八、端口转发与隧道
  9. [九、SSH 常用命令与实战](#九、SSH 常用命令与实战)
  10. [十、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 协议的关键在于抓住两条主线:

  1. 密钥交换:DH 算法如何让双方"隔空"生成相同的会话密钥
  2. 分层安全:非对称加密保护密钥交换,对称加密保护数据传输
相关推荐
lingran__2 小时前
Linux 基础常用指令万字详解(上)|文件目录命令,结合底层原理剖析
linux·运维·服务器·后端·centos·linux基础指令
各类产品分享3 小时前
电力行业AR智能运维哪个品牌好
运维·ar·ar巡检
GIR1233 小时前
研究更新:2026年网络协议分析工具发展前景与竞争格局报告(附市场占有率与产业链图谱)
网络·网络协议
贾天佑忆月 迷失的昵3 小时前
客户端与服务器持续同步解析(轮询,comet,WebSocket)
运维·服务器·websocket
刘某的Cloud3 小时前
Galera Cluster mariadb 生产环境常见问题排查与运维指南
linux·运维·数据库·mariadb·集群高可用
70asunflower3 小时前
Linux 性能排查分析完全教程
linux·运维
zhangfeng11334 小时前
宝塔8 升级到 11导致 服务器无法访问外网dns失效了,无法访问bt.cn 解决方法 测试通过
运维·服务器
兵bing5 小时前
Docker Compose 配置文件归纳总结-千问
运维·docker·容器
半支烟隐 pzishuo5 小时前
HTTP Live Streaming(HLS)直播技术分析与实现
网络·网络协议·http