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. 分层安全:非对称加密保护密钥交换,对称加密保护数据传输
相关推荐
夜月yeyue9 小时前
SOME/IP-SD 服务发现故障
网络·单片机·网络协议·tcp/ip·安全·服务发现
shujudang10 小时前
从数据闭环到 Agent 协同:企业营销自动化如何演进为智能运营?
大数据·运维·人工智能·数据分析·自动化
小白说大模型10 小时前
Codex 实战:用 AI 写运维脚本
大数据·运维·网络·人工智能·机器学习·prompt
2501_9160088910 小时前
iOS App 请求地址查看,不用配置看到 App 调了哪些接口
网络协议·计算机网络·网络安全·ios·adb·https·udp
数字护盾(和中)10 小时前
和中科技剖析 EDR 绕过全链路,AMSI、ETW 规避技术与防御对策
运维·网络·人工智能·科技·安全·web安全
天远Date Lab12 小时前
零信任架构实战:基于天远普通维保查询构建自动化车辆收车评估网关
运维·人工智能·架构·自动化
流星白龙12 小时前
【Docker】9.Docker 镜像仓库实战
运维·docker·容器
张洛闻Eren12 小时前
云原生k8s【第六课】:K8s 访问控制
运维·docker·云原生·容器·kubernetes·k8s
苹果嘉尔1213812 小时前
Linux系统编程——网络(TCP)
linux·运维·服务器
网安蟹佬霸12 小时前
区块链与智能合约安全实战:从Solidity审计到DeFi漏洞深度剖析
运维·前端·网络·安全·自动化·区块链·智能合约