SSH

返回 计算机网络

SSH(Secure Shell)是建立在 TCP 之上的加密远程登录与隧道协议,默认端口 22。它替代了明文的 Telnet / rlogin / rsh,提供加密、服务端身份认证、客户端身份认证与完整性校验。

SSH 与 TLS 都做「加密信道」,但二者是独立的协议体系:TLS 用 X.509 证书 + CA 信任链;SSH 用「主机公钥指纹 + 公钥/密码」认证,没有 CA。


协议分层

SSH 协议(RFC 4251–4254)分三层,自下而上:

协议职责
传输层SSH-TRANS服务端身份认证、密钥协商、加密与完整性、可选压缩
认证层SSH-AUTH客户端身份认证(公钥/密码/键盘交互等)
连接层SSH-CONN在一条加密连接上多路复用多个「通道」(shell、exec、端口转发、X11)
应用:远程 shell / scp / sftp / 端口转发
       ↓ 多路复用
连接层 SSH-CONN(channel)
       ↓
认证层 SSH-AUTH(验证你是谁)
       ↓
传输层 SSH-TRANS(加密 + 验证服务端是谁)
       ↓
传输层 TCP(默认 22 端口)

连接握手流程

客户端                                          服务端
  │── TCP 三次握手 ─────────────────────────────►│
  │◄─ 版本协商 SSH-2.0-... ───────────────────────►│
  │── KEXINIT(支持的算法列表)────────────────►│
  │◄─ KEXINIT(支持的算法列表)──────────────────│
  │      ── 密钥交换 ECDH / DH ──                  │
  │◄─ 服务端主机公钥 + 签名 ─────────────────────│  ← 验证服务端身份
  │      (客户端核对 known_hosts 指纹)          │
  │── NEWKEYS(启用对称加密)──────────────────►│
  │── 用户认证(公钥 / 密码)──────────────────►│  ← 验证客户端身份
  │◄─ 认证成功 ──────────────────────────────────│
  │         打开通道,加密会话开始                 │
  1. 算法协商:双方交换支持的密钥交换、加密、MAC、压缩算法,各取双方都支持的首选项。
  2. 密钥交换(KEX):用 ECDH / DH 协商出一次性的会话对称密钥(前向保密)。
  3. 服务端认证:服务端用主机私钥对握手内容签名,客户端用 known_hosts 里记录的主机公钥校验 → 防中间人。
  4. 客户端认证:再验证「你是哪个用户」。

两种「密钥」别混淆

名称谁持有作用存放
主机密钥(Host Key)服务器证明「服务器是不是你以为的那台」服务端 /etc/ssh/ssh_host_*_key;客户端记录公钥指纹于 ~/.ssh/known_hosts
用户密钥(User Key)用户证明「你是不是这个用户」私钥 ~/.ssh/id_ed25519;公钥放服务端 ~/.ssh/authorized_keys

第一次连接时出现的提示就是在确认主机密钥指纹:

The authenticity of host 'example.com' can't be established.
ED25519 key fingerprint is SHA256:xxxx...
Are you sure you want to continue connecting (yes/no)?

yes 会把该公钥写入 known_hosts首次连接(TOFU,Trust On First Use)是 SSH 信任模型的薄弱点——若首次就被中间人劫持,指纹会被污染。生产环境可用 SSH 证书或带外核对指纹规避。


客户端认证方式

方式原理说明
公钥认证服务端用 authorized_keys 里的公钥发起挑战,客户端用私钥签名应答最推荐;私钥永不离开本机
密码认证提交用户名 + 密码易受暴力破解,生产建议关闭
键盘交互服务端推送多步提问(常用于 2FA / OTP)可叠加 TOTP 等
基于主机以客户端主机身份认证较少用
GSSAPI / Kerberos企业域统一认证内网 SSO

生成密钥对

# 推荐 Ed25519,短、快、安全
ssh-keygen -t ed25519 -C "you@example.com"
 
# 兼容旧系统时用 RSA,长度至少 3072/4096
ssh-keygen -t rsa -b 4096 -C "you@example.com"

生成 ~/.ssh/id_ed25519(私钥,绝不外传)与 id_ed25519.pub(公钥)。

部署公钥到服务器

# 自动追加到远端 authorized_keys
ssh-copy-id user@host
 
# 手动等价:把 .pub 内容追加到远端 ~/.ssh/authorized_keys

常用命令

# 基本登录
ssh user@host
ssh -p 2222 user@host          # 指定端口
 
# 远程执行单条命令
ssh user@host "df -h"
 
# 文件传输
scp file.txt user@host:/tmp/   # 上传
scp user@host:/tmp/file.txt .  # 下载
sftp user@host                 # 交互式传输
 
# 调试连接(逐步打印握手/认证过程)
ssh -vvv user@host

端口转发(SSH 隧道)

SSH 可把任意 TCP 流量套进加密通道,是它最强大的能力之一。

类型命令作用
本地转发 -Lssh -L 8080:db:5432 user@gw本地 8080 经跳板机转发到 db:5432(访问内网服务)
远程转发 -Rssh -R 9000:localhost:3000 user@public远端 9000 转回本地 3000(内网穿透/暴露本地服务)
动态转发 -Dssh -D 1080 user@host在本地起 SOCKS5 代理,流量经 SSH 出口 → 代理
本地转发 -L:
  本机:8080 ──加密──► 跳板机 ──明文──► 内网 db:5432

远程转发 -R:
  公网:9000 ──加密──► 你的机器 ──► localhost:3000

客户端配置 ~/.ssh/config

为常用主机定义别名,免去重复输入:

Host myserver
    HostName 203.0.113.10
    User deploy
    Port 2222
    IdentityFile ~/.ssh/id_ed25519
    ServerAliveInterval 60        # 心跳保活,防 NAT 超时断连
 
# 通过跳板机访问内网(堡垒机)
Host internal
    HostName 10.0.0.5
    ProxyJump myserver            # 等价老写法 ProxyCommand

之后直接 ssh myserver 即可。


服务端加固(/etc/ssh/sshd_config

配置项推荐值作用
PermitRootLoginno / prohibit-password禁止 root 直接密码登录
PasswordAuthenticationno关闭密码,仅留公钥
PubkeyAuthenticationyes启用公钥认证
Port非 22改端口减少自动化扫描噪音(非真正安全措施)
AllowUsers / AllowGroups白名单限制可登录用户
MaxAuthTries3限制单连接尝试次数
X11Forwardingno(无需时)减少攻击面

改完需重载:sudo systemctl reload sshd系统服务

配合 fail2ban(封禁暴力破解 IP)、防火墙白名单、SSH 证书等进一步加固 → 网络安全


SSH 证书(超越 known_hosts / authorized_keys)

大规模场景下,逐台管理 known_hostsauthorized_keys 很难。SSH 支持用一个 CA 密钥签发短期证书:

证书类型解决的问题
主机证书客户端只需信任 CA,无需逐台记录主机指纹 → 消除 TOFU 风险
用户证书服务端只需信任 CA,无需逐台分发公钥;证书可设短有效期
# 用 CA 私钥签发用户证书,有效期 1 天
ssh-keygen -s ca_key -I user_id -n deploy -V +1d id_ed25519.pub

这是 HashiCorp Vault、Teleport、Smallstep 等零信任 SSH 方案的基础。


与 TLS 的对比

维度SSHTLS
典型用途远程登录、文件传输、隧道加密 Web/邮件等应用流量(HTTPS、SMTPS)
服务端信任主机公钥指纹(TOFU)或 SSH-CAX.509 证书 + 公共 CA 信任链
客户端认证公钥/密码/键盘交互(常用)默认不验证,可选 mTLS
默认端口22随应用(HTTPS 443)
多路复用内置通道机制由上层(HTTP/2)负责

常见问题排查

现象可能原因
Permission denied (publickey)公钥没进 authorized_keys、私钥权限太松、用户名错
Host key verification failed服务端主机密钥变了(重装/换机/被劫持);核实后删 known_hosts 对应行
私钥被拒/忽略~/.ssh 须 700、私钥须 600,权限过宽会被 OpenSSH 拒绝
连接卡住/频繁断开NAT 超时;设 ServerAliveInterval 保活
连接慢反向 DNS 解析;服务端设 UseDNS no
# 主机密钥变更后,移除旧记录
ssh-keygen -R example.com

相关

  • TLS — 另一套加密信道,基于 CA 证书
  • TCP — SSH 运行其上,默认 22 端口
  • 代理 — 动态转发 -D 提供 SOCKS5 代理
  • 网络安全 — 加固、暴力破解防护
  • 通信协议 — 协议栈中的位置
  • Socket — 底层连接抽象
  • 网络性能 — 握手 RTT 与保活