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(启用对称加密)──────────────────►│
│── 用户认证(公钥 / 密码)──────────────────►│ ← 验证客户端身份
│◄─ 认证成功 ──────────────────────────────────│
│ 打开通道,加密会话开始 │
- 算法协商:双方交换支持的密钥交换、加密、MAC、压缩算法,各取双方都支持的首选项。
- 密钥交换(KEX):用 ECDH / DH 协商出一次性的会话对称密钥(前向保密)。
- 服务端认证:服务端用主机私钥对握手内容签名,客户端用
known_hosts里记录的主机公钥校验 → 防中间人。 - 客户端认证:再验证「你是哪个用户」。
两种「密钥」别混淆
| 名称 | 谁持有 | 作用 | 存放 |
|---|---|---|---|
| 主机密钥(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 流量套进加密通道,是它最强大的能力之一。
| 类型 | 命令 | 作用 |
|---|---|---|
本地转发 -L | ssh -L 8080:db:5432 user@gw | 把本地 8080 经跳板机转发到 db:5432(访问内网服务) |
远程转发 -R | ssh -R 9000:localhost:3000 user@public | 把远端 9000 转回本地 3000(内网穿透/暴露本地服务) |
动态转发 -D | ssh -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)
| 配置项 | 推荐值 | 作用 |
|---|---|---|
PermitRootLogin | no / prohibit-password | 禁止 root 直接密码登录 |
PasswordAuthentication | no | 关闭密码,仅留公钥 |
PubkeyAuthentication | yes | 启用公钥认证 |
Port | 非 22 | 改端口减少自动化扫描噪音(非真正安全措施) |
AllowUsers / AllowGroups | 白名单 | 限制可登录用户 |
MaxAuthTries | 3 | 限制单连接尝试次数 |
X11Forwarding | no(无需时) | 减少攻击面 |
改完需重载:sudo systemctl reload sshd → 系统服务。
配合 fail2ban(封禁暴力破解 IP)、防火墙白名单、SSH 证书等进一步加固 → 网络安全。
SSH 证书(超越 known_hosts / authorized_keys)
大规模场景下,逐台管理 known_hosts 和 authorized_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 的对比
| 维度 | SSH | TLS |
|---|---|---|
| 典型用途 | 远程登录、文件传输、隧道 | 加密 Web/邮件等应用流量(HTTPS、SMTPS) |
| 服务端信任 | 主机公钥指纹(TOFU)或 SSH-CA | X.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