SSH 实战与排错 — 抓包、密钥认证、端口转发与故障定位

Wireshark 抓 SSH、ssh/scp/sftp/ssh-keygen 全套命令、三种转发实操与经典报错排查 / 应用层 / TCP 22

这篇你能学到

  • SSH 抓包能看到什么、看不到什么——为什么排错不能指望抓包,而要靠 ssh -vvv 和服务端日志。
  • 从生成密钥、分发公钥、用 agent 免密,到 scp/sftp/rsync 传文件,再到 -L/-R/-D 三种端口转发的完整命令手册。
  • 七类高频报错(publickey 被拒、主机密钥变更、算法不匹配、连接慢、被踢下线、转发不生效等)的结论先行排查路径,以及 sshd 加固基线、协议对比与面试速查。

1. 抓包观察

1.1 Wireshark 显示过滤式

这组过滤式能干什么:把 SSH 会话按阶段拆开看。重点是 20(算法协商)和 21(切换密钥)这两个编号——20 号包里能看到双方支持的全部算法(排查"算法不匹配"的唯一依据),21 号包之后就只剩密文了。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
ssh # SSH 解析器
tcp.port == 22 # 含非标端口时改用实际端口
ssh.protocol # 明文版本串 "SSH-2.0-OpenSSH_9.6p1"
ssh.message_code == 20 # SSH_MSG_KEXINIT(算法协商,明文可读)
ssh.message_code == 21 # SSH_MSG_NEWKEYS(此后全部加密)
ssh.message_code == 30 || ssh.message_code == 31 # KEX_ECDH_INIT / REPLY
ssh.kex_algorithms # 客户端/服务端支持的 KEX 算法清单
ssh.encryption_algorithms_client_to_server
ssh.host_key.type # 服务端主机密钥类型
tcp.port == 22 && tcp.flags.reset == 1 # 被拒绝/重置
tcp.port == 22 && tcp.analysis.retransmission # 丢包导致的卡顿

命令行:

这组命令能干什么:把 SSH 流量抓成文件,再用 tshark 提取出每个包的版本串和消息编号,快速判断握手走到第几步就断了;最后一条专门把算法协商的细节打印出来做比对。

1
2
3
4
sudo tcpdump -i any -nn 'tcp port 22' -w ssh.pcap
tshark -r ssh.pcap -Y ssh -T fields -e frame.number -e ssh.protocol -e ssh.message_code
# 只看算法协商细节
tshark -r ssh.pcap -Y 'ssh.message_code==20' -V | grep -A2 -E 'kex_algorithms|encryption_algorithms'

1.2 典型字段说明(能看到什么、看不到什么)

阶段抓包可见内容用途
版本交换完全明文SSH-2.0-OpenSSH_9.6p1 Ubuntu-3ubuntu13.5版本指纹、漏洞面判断、合规扫描
KEXINIT (20)明文:双方全部算法名单、16 字节 cookie排查"no matching key exchange method found"类算法不匹配
KEX_ECDH_REPLY (31)服务端主机公钥、临时公钥、签名核对主机密钥类型与指纹
NEWKEYS (21) 之后只剩 Encrypted packet (len=xx)用户名、口令、命令、输出全部不可见
包长模式加密后仍能看到包大小与时序侧信道:交互式击键会产生大量 3652 字节小包;sftp 传输为大包连发
TCP 层重传、零窗口、RTT定位"SSH 卡顿/断连"是网络问题还是服务端问题

重要结论:SSH 抓包看不到任何凭据。排错时不要指望从包里读命令,应转向服务端日志与 ssh -vvv

2. 常用命令 / 配置

2.1 连接与调试

这组命令能干什么:覆盖日常连接的各种姿势——换端口、指定私钥、只跑一条命令、走跳板机。排错时第一个该敲的是 ssh -vvv,它会把握手和认证的每一步都打印出来;ssh -G 则告诉你各层配置文件合并后到底生效了什么。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
ssh alice@192.168.1.10 # 基本登录
ssh -p 2222 alice@host # 非标端口
ssh -i ~/.ssh/id_ed25519 alice@host # 指定私钥
ssh alice@host 'uptime; df -h' # 执行单条命令(exec 通道,不分配 pty)
ssh -t alice@host 'sudo systemctl status nginx' # 强制分配 pty(sudo 需要)
ssh -v alice@host # 调试;-vv / -vvv 更详细(排错第一命令)
ssh -J bastion.example.com alice@10.0.0.5 # ProxyJump 跳板(优于 -A agent 转发)
ssh -o StrictHostKeyChecking=accept-new alice@host # 首次自动接受但后续校验
ssh -Q kex ; ssh -Q cipher ; ssh -Q mac ; ssh -Q key # 查询本地支持的算法
ssh -G host # 打印最终生效的配置(含 ~/.ssh/config 合并结果)

2.2 密钥生成与分发

这组命令能干什么:造一把属于你的钥匙,再把"锁孔"(公钥)装到服务器上,从此免密登录。私钥永远留在本机,只有 .pub 结尾的公钥才需要上传。最后两条用于登录前带外核对服务器指纹,是防中间人的关键步骤。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
ssh-keygen -t ed25519 -C "alice@laptop" # 推荐(短、快、安全)
ssh-keygen -t rsa -b 4096 -C "alice@laptop" # 兼容老系统
ssh-keygen -t ed25519-sk -C "fido2-key" # 绑定 FIDO2 硬件密钥
ssh-keygen -lf ~/.ssh/id_ed25519.pub # 查看指纹(SHA256)
ssh-keygen -lf ~/.ssh/id_ed25519.pub -E md5 # MD5 格式指纹
ssh-keygen -p -f ~/.ssh/id_ed25519 # 修改私钥口令
ssh-keygen -y -f ~/.ssh/id_ed25519 > id_ed25519.pub # 从私钥恢复公钥

ssh-copy-id -i ~/.ssh/id_ed25519.pub alice@host # 分发公钥(推荐)
# 无 ssh-copy-id 时的等价手工做法
cat ~/.ssh/id_ed25519.pub | ssh alice@host \
  'mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'

# 服务端主机密钥指纹(登录前带外核对,防中间人)
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
ssh-keyscan -t ed25519 host # 远程抓取主机公钥

2.3 ssh-agent 与 known_hosts

这组命令能干什么:前半段让你输一次私钥口令就管一整天(agent 在内存里替你保管解密后的私钥);后半段管理"已认识的服务器"名单——服务器重装后报主机密钥变更告警,就是用 ssh-keygen -R 删掉旧记录。

1
2
3
4
5
6
7
8
9
eval "$(ssh-agent -s)" # 启动 agent
ssh-add ~/.ssh/id_ed25519 # 加载私钥(免重复输口令)
ssh-add -l # 列出已加载密钥
ssh-add -D # 清空
ssh-add -t 3600 ~/.ssh/id_ed25519 # 一小时后自动过期

ssh-keygen -F host # 查询 known_hosts 中某主机记录
ssh-keygen -R host # 删除该主机记录(主机密钥变更后用)
ssh-keygen -R '[host]:2222' # 非标端口的记录格式

2.4 文件传输

这组命令能干什么:三种传文件方式各有适用场景——scp 适合随手拷一两个文件(注意端口参数是大写 -P,和 ssh 的小写 -p 相反);sftp 适合交互式浏览远端目录;rsync 适合大文件和增量同步,支持断点续传。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
scp file.txt alice@host:/tmp/ # 上传
scp alice@host:/var/log/app.log ./ # 下载
scp -r dir/ alice@host:/opt/ # 递归目录
scp -P 2222 -i ~/.ssh/id_ed25519 f alice@host:~ # 注意 scp 是大写 -P
scp -3 alice@A:/f bob@B:/f # 经本地中转的主机间拷贝

sftp alice@host # 交互式:put/get/ls/lcd/mkdir/bye
sftp -b batch.txt alice@host # 批处理模式
echo "get /var/log/syslog" | sftp -b - alice@host

rsync -avzP -e 'ssh -p 2222' dir/ alice@host:/opt/dir/ # 断点续传/增量同步(大文件首选)

2.5 端口转发三形态(面试必考)

这组命令能干什么:把 SSH 当隧道用。-L 是"拉进来"——内网数据库映射到你本机端口,本地工具直接连;-R 是"推出去"——把你本机的服务暴露到远端服务器上,等于内网穿透;-D 是"全都走"——本地起一个 SOCKS5 代理,浏览器整体从内网出口访问。-N 表示"只打隧道不开 shell"。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# ① 本地转发 -L:把远端服务"拉到"本地
# 本地 13306 → 经 gw → gw 能访问的 db.internal:3306
ssh -N -L 13306:db.internal:3306 alice@gw
mysql -h 127.0.0.1 -P 13306 -u root -p

# ② 远程转发 -R:把本地服务"推到"远端(内网穿透)
# 远端 gw 的 8080 → 经 SSH → 本机 localhost:80
ssh -N -R 8080:localhost:80 alice@gw
# 让 gw 上的 8080 对外可访问,需服务端 sshd_config: GatewayPorts yes
ssh -N -R 0.0.0.0:8080:localhost:80 alice@gw

# ③ 动态转发 -D:本地 SOCKS5 代理
ssh -N -D 1080 alice@gw
curl --socks5-hostname 127.0.0.1:1080 https://internal.example.com
export ALL_PROXY=socks5h://127.0.0.1:1080

# 常用组合:-N 不执行远程命令,-f 后台,-C 压缩
ssh -fNC -L 13306:db:3306 alice@gw
# 断线自动重连(配合 autossh)
autossh -M 0 -fNC -o ServerAliveInterval=30 -L 13306:db:3306 alice@gw

2.6 ~/.ssh/config 客户端配置(强烈推荐)

这段配置能干什么:把一长串连接参数固化成一个短名字,以后 ssh db01 一条命令搞定跳板加认证。ControlMaster 让后续连接复用已有 TCP,第二次连接几乎秒开ServerAliveInterval 则靠保活包防止 NAT 把空闲连接掐掉。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
Host *
    ServerAliveInterval 30
    ServerAliveCountMax 3
    ControlMaster auto
    ControlPath ~/.ssh/cm-%r@%h:%p
    ControlPersist 10m
    HashKnownHosts yes
    AddKeysToAgent yes

Host gw
    HostName bastion.example.com
    User alice
    Port 2222
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

Host db01
    HostName 10.0.0.5
    User deploy
    ProxyJump gw # 经 gw 跳板,无需 agent 转发

之后直接 ssh db01 即可。ControlMaster 让第二次连接复用已有 TCP,秒开。

2.7 服务端(sshd)管理与加固

这组命令能干什么:在服务器端查看服务状态、验证配置、看认证日志。sshd -t 是改配置后的救命符——它做语法检查,能避免你重启服务后把自己锁在门外;sshd -T 则打印所有实际生效的值(包括你没写在配置文件里的默认值)。

1
2
3
4
5
6
7
8
9
sudo systemctl status sshd # Debian/Ubuntu 服务名可能是 ssh
sudo systemctl restart sshd
sudo sshd -t # 语法检查(改配置后必做,防止把自己锁在外面)
sudo sshd -T | grep -Ei 'permitroot|passwordauth|pubkey|port|ciphers' # 打印生效配置
sudo ss -tlnp | grep :22
sudo journalctl -u sshd -f # 实时日志
sudo tail -f /var/log/auth.log # Debian/Ubuntu
sudo tail -f /var/log/secure # RHEL/CentOS
sudo sshd -d -p 2223 # 前台调试模式,另开端口测试

/etc/ssh/sshd_config 加固基线:

这段配置能干什么:一份可以直接抄的加固清单。核心思路是只留公钥认证、不许 root 直登、限定允许的用户、只用现代加密算法,再关掉用不到的转发功能缩小攻击面。UseDNS no 是顺手解决"登录要等十几秒"的经典配置。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
Port 22
PermitRootLogin prohibit-password # 或 no
PasswordAuthentication no # 仅公钥
PubkeyAuthentication yes
KbdInteractiveAuthentication no
PermitEmptyPasswords no
MaxAuthTries 3
LoginGraceTime 30
ClientAliveInterval 300
ClientAliveCountMax 2
AllowUsers alice deploy # 或 AllowGroups sshusers
X11Forwarding no
AllowTcpForwarding no # 纯登录机可关;跳板机需保留
GatewayPorts no
UseDNS no # 避免反向解析导致登录变慢

KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com
HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256

改配置铁律:先 sshd -t 校验,再保留一个已登录会话的前提下 restart,用新窗口验证能登录后才关旧会话。

3. 常见故障与排错

3.1 Permission denied (publickey)

先记住结论十有八九是权限问题,不是密钥问题——~/.sshauthorized_keys、家目录只要对组或其他人可写,sshd 就会直接拒绝。先 chmod 一遍再查别的。

原因排查与修复
权限过宽(最高频)chmod 700 ~/.ssh; chmod 600 ~/.ssh/authorized_keys; chmod 700 $HOME(家目录不能对组/其他人可写)
公钥未正确写入服务端 cat ~/.ssh/authorized_keys,确认是一行完整ssh-ed25519 AAAA... comment
客户端选错私钥ssh -vvvOffering public key: 行;用 -i + IdentitiesOnly yes 锁定
SELinux 上下文错误restorecon -Rv ~/.ssh
服务端禁用了公钥sshd -T | grep pubkeyauthentication
用户不在白名单sshd -T | grep -E 'allowusers|allowgroups'
密钥类型被禁ssh-rsa(SHA-1) 在 OpenSSH 8.8+ 默认禁用 → 换 ed25519,或临时 -o PubkeyAcceptedAlgorithms=+ssh-rsa

排查命令组合:

这两条能干什么:第一条从客户端视角看"我到底递交了哪把钥匙、服务端还允许哪些方法";第二条从服务端日志看"为什么拒绝"——服务端日志通常把真实原因写得更清楚,两边对照最快定位。

1
2
ssh -vvv alice@host 2>&1 | grep -E 'Offering|Authentications|debug1: Next auth'
sudo journalctl -u sshd | tail -30 # 服务端侧原因通常写得更明确

3.2 Host key verification failed / 主机密钥变更告警

先记住结论这个告警本身是保护机制生效了,不是故障。先判断是"服务器重装/迁移"这类合法变更,还是真有中间人;确认无误再删旧记录,绝不要用 StrictHostKeyChecking=no 一关了之

1
@@@@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @@@@
  • 先判断原因:服务器重装/迁移/负载均衡后端变化 → 正常;否则怀疑中间人。
  • 带外核对指纹:在服务器本机执行 ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub,与客户端提示的 SHA256 比对。
  • 确认无误后:ssh-keygen -R host(或 ssh-keygen -R '[host]:2222')再重连。
  • 不要图省事用 StrictHostKeyChecking=no,那等于放弃中间人防护。

3.3 no matching key exchange method found / no matching cipher found

先记住结论这不是配置错了,是双方"没有共同语言"——新客户端把弱算法都删了,老设备又只会弱算法,交集为空。追加算法是应急,升级设备固件才是根治。

新旧版本算法集不相交(如新客户端连老设备,或加固过的服务端):

这组命令能干什么:第一条先看清对端到底支持哪些算法(从明文的 KEXINIT 包里读);第二条用 + 号把缺失的老算法追加到本地列表末尾(注意是追加不是覆盖,否则会连带禁掉现代算法)。

1
2
3
4
5
6
ssh -vvv host 2>&1 | grep -E 'kex_algorithms|peer server KEXINIT' # 看对端支持什么
# 临时以 + 追加而非覆盖
ssh -o KexAlgorithms=+diffie-hellman-group1-sha1 \
    -o HostKeyAlgorithms=+ssh-rsa \
    -o PubkeyAcceptedAlgorithms=+ssh-rsa \
    -c aes128-cbc admin@old-switch

这是降级兼容手段,仅用于老网络设备;根治办法是升级设备固件。

3.4 连接建立很慢(10~30 秒)

先记住结论慢在哪一步决定了原因——认证之前就慢,通常是服务端反向 DNS 或 GSSAPI 探测在超时;认证成功之后才慢,那是登录脚本的问题,跟 SSH 协议无关。

原因验证解决
服务端反向 DNS 超时ssh -vvv 停在 debug1: SSH2_MSG_SERVICE_ACCEPT 前后sshd_config: UseDNS no
GSSAPI/Kerberos 探测日志中大量 gssapi 尝试客户端 GSSAPIAuthentication no
登录脚本慢认证成功后才慢检查 ~/.bashrc/etc/profile.d/pam_motdlandscape-sysinfo
MTU / 分片大包卡住,小交互正常ping -M do -s 1400 host 试探;调 MTU
IPv6 优先但不通-4 后立即变快ssh -4AddressFamily inet

3.5 会话空闲后被断开(Connection closed by remote host / broken pipe)

先记住结论多半不是 SSH 断了,是中间的 NAT/防火墙把空闲连接的会话表项老化删掉了——加保活包让连接"看起来一直有流量"即可;跑长任务则应该直接上 tmux

这两段配置能干什么:客户端每 30 秒发一次保活探测、连续 6 次无响应才断开;服务端反向每 60 秒探一次、3 次无响应断开。两边都配上,空闲连接就不会被中间设备悄悄掐断。

1
2
3
4
5
# 客户端 ~/.ssh/config
Host *
    ServerAliveInterval 30
    ServerAliveCountMax 6
    TCPKeepAlive yes
1
2
3
# 服务端 sshd_config
ClientAliveInterval 60
ClientAliveCountMax 3

NAT/防火墙会话老化是最常见根因(保活包让 NAT 表项不过期)。长任务建议直接用 tmux / screen,断线也不丢进程。

3.6 端口转发不生效

先记住结论先分清是"隧道没建起来"还是"隧道通了但目标不通"——本地端口连不上属于前者(多半忘了 -N 或端口被占),能连但被拒属于后者(服务端到目标不通,或被 AllowTcpForwarding 策略挡住)。

现象原因
-L 本地端口连不上-N 未加导致进程退出;或本地端口被占用(ss -tlnp | grep 13306
-L 通但目标拒绝服务端到目标不通:登上 gw 执行 nc -zv db 3306 验证
-R 只能本机访问服务端需 GatewayPorts yes(默认 no 只绑 127.0.0.1)
全部转发失败服务端 AllowTcpForwarding noPermitOpen 限制;sshd -T | grep -i forwarding
SOCKS 代理 DNS 泄漏socks5h://(h = 由代理端解析域名)而非 socks5://

3.7 其他高频错误速查

先记住结论refused 是服务没监听、timed out 是包被防火墙丢了——这两个报错一眼就能区分"服务问题"和"网络问题",其余多为客户端本地配置或密钥状态问题。

报错含义与处理
Connection refused端口没监听/服务未启:ss -tlnp | grep 22
Connection timed out防火墙 DROP 或路由不通:nc -zv host 22traceroute
Too many authentication failuresagent 里密钥太多被逐个尝试超限:-o IdentitiesOnly=yes -i <key>
Bad owner or permissions on ~/.ssh/configchmod 600 ~/.ssh/config
sign_and_send_pubkey: signing failedagent 中私钥失效/硬件密钥未插:ssh-add -D 后重加载
kex_exchange_identification: read: Connection reset被 fail2ban/防火墙拦截,或对端不是 SSH 服务
Unable to negotiate ... no matching host key type见 3.3,追加 HostKeyAlgorithms=+ssh-rsa
REMOTE HOST IDENTIFICATION HAS CHANGED见 3.2

4. 与其他协议对比

维度SSHTelnetTLS/HTTPSIPSec VPNRDP
端口TCP 22TCP 23TCP 443UDP 500/4500, ESPTCP/UDP 3389
规范RFC 4251~4254RFC 854/855RFC 8446RFC 4301 等MS-RDPBCGR
加密内建(自有密码套件)(全明文)内建(X.509 PKI)网络层加密TLS + CredSSP
服务端身份主机密钥 TOFU / SSH CACA 签发证书链IKE 证书或 PSK多为自签名证书
客户端认证公钥/口令/2FA/证书/Kerberos明文口令可选客户端证书证书/PSK/EAP域账号 + NLA
传输内容字符流 + 任意 TCP 隧道字符流HTTP 等应用数据任意 IP 报文图形与设备重定向
多路复用通道(channel)HTTP/2 stream无(IP 层)MCS 虚拟通道
文件传输scp / sftp / rsyncHTTP 上传下载依赖上层驱动器重定向
典型场景Linux 运维、Git、自动化端口探测、老设备应急Web站点互联Windows 图形运维

关系记忆Telnet + 加密 + 公钥认证 + 隧道 = SSHSSH 之于命令行 ≈ HTTPS 之于 Web

5. 速查表 / 常见面试题

5.1 命令速查

目标命令
生成密钥ssh-keygen -t ed25519 -C "备注"
分发公钥ssh-copy-id -i ~/.ssh/id_ed25519.pub user@host
查看指纹ssh-keygen -lf ~/.ssh/id_ed25519.pub
删除旧主机记录ssh-keygen -R host
调试连接ssh -vvv user@host
打印生效配置客户端 ssh -G host / 服务端 sshd -T
配置语法检查sshd -t
本地转发ssh -N -L 本地端口:目标host:目标端口 网关
远程转发ssh -N -R 远端端口:localhost:本地端口 网关
SOCKS 代理ssh -N -D 1080 网关
跳板ssh -J bastion user@target
只执行命令ssh user@host 'command'
保持会话tmux / autossh -M 0

5.2 关键文件与默认值

项目路径 / 值
客户端配置~/.ssh/config(600)、/etc/ssh/ssh_config
服务端配置/etc/ssh/sshd_config/etc/ssh/sshd_config.d/*.conf
用户私钥/公钥~/.ssh/id_ed25519(600)/ .pub(644)
授权公钥~/.ssh/authorized_keys(600),~/.ssh 目录 700
已知主机~/.ssh/known_hosts/etc/ssh/ssh_known_hosts
主机密钥/etc/ssh/ssh_host_{ed25519,rsa,ecdsa}_key
日志/var/log/auth.log(Debian)、/var/log/secure(RHEL)、journalctl -u sshd
默认 rekey 阈值1 GB 或 1 小时
默认通道窗口2 MB,最大包 32 KB

5.3 高频面试题

Q1:SSH 的三层协议分别做什么? A:**传输层协议(RFC 4253)**负责算法协商、密钥交换、服务端主机认证、加密与完整性;**认证协议(RFC 4252)**在加密通道内认证客户端用户;**连接协议(RFC 4254)**把一条加密连接复用成多个通道(shell、sftp、端口转发、X11)。

Q2:SSH 和 Telnet 的核心区别? A:Telnet 全程明文、无服务端身份验证、只能口令认证、无隧道能力;SSH 先建加密通道再认证,支持主机密钥校验、公钥/2FA 认证、通道复用与端口转发。抓包时 Telnet 能逐字看到口令,SSH 只能看到版本串和算法名单。

Q3:公钥认证的完整过程?私钥会不会传到服务器? A:不会。客户端先用公钥"探测"服务端是否接受(服务端在 authorized_keys 中查找并回 PK_OK),然后客户端用私钥对包含 session_id 的数据签名发给服务端,服务端用 authorized_keys 中的公钥验签。私钥始终不出本机,且签名绑定本次会话无法重放。

Q4:known_hosts 是干什么的?主机密钥变更告警一定是攻击吗? A:记录服务端主机公钥,实现 TOFU 信任,防止中间人。变更告警最常见的合法原因是服务器重装、迁移、更换负载均衡后端、容器重建。处理方式是带外核对指纹ssh-keygen -R host,而不是盲目 StrictHostKeyChecking=no

Q5:-L-R-D 的区别?举个场景。 A:-L 本地转发——把远端/内网服务映射到本地端口(本地连数据库 ssh -L 13306:db:3306 gw);-R 远程转发——把本机服务暴露到远端(内网穿透,让公网机器访问家里的 Web ssh -R 8080:localhost:80 vps);-D 动态转发——本地起 SOCKS5 代理,目标地址由应用运行时决定(浏览器走内网)。

Q6:为什么建议用 ed25519 而不是 RSA? A:Ed25519 密钥仅 256 位却提供约 128 位安全强度,签名/验签快、密钥短、实现天然抗时序侧信道,且不依赖高质量随机数(确定性签名)。RSA 需要 3072/4096 位才等强,且 ssh-rsa(SHA-1 签名)已在 OpenSSH 8.8+ 默认禁用(应使用 rsa-sha2-256/512)。

Q7:SSH 为什么还需要通道级流控?TCP 不是有吗? A:因为一条 TCP 上复用多个通道。若只靠 TCP 流控,某个读取缓慢的通道会阻塞整条连接上的所有通道。SSH 给每通道独立窗口(CHANNEL_WINDOW_ADJUST 补充),实现通道间隔离。

Q8:什么是 rekey?为什么需要? A:会话中期重新执行密钥交换生成新密钥。OpenSSH 默认 1 GB 数据或 1 小时触发。目的是限制单个密钥保护的数据量(降低密码分析与 IV 重用风险),并增强前向保密。

Q9:ProxyJump 和 Agent Forwarding 有什么区别?该用哪个? A:ForwardAgent 把本地 agent 的签名能力暴露给跳板机,跳板机被攻陷时攻击者可用你的身份连其他机器;ProxyJump (-J) 只是把跳板机当 TCP 隧道,认证仍在本地完成,私钥能力不外泄。优先用 -J

Q10:如何加固一台对公网开放的 SSH 服务器? A:① 仅公钥认证(PasswordAuthentication no);② PermitRootLogin no;③ AllowUsers/AllowGroups 白名单;④ 算法白名单禁用弱套件;⑤ MaxAuthTries 3 + fail2ban;⑥ 改非标端口降噪;⑦ 关闭不需要的 X11/TCP 转发;⑧ 保持 OpenSSH 版本最新(如修复 Terrapin CVE-2023-48795、regreSSHion CVE-2024-6387);⑨ 有条件上 SSH 证书 CA 与 MFA。

Q11:SFTP 和 FTPS 是一回事吗? A:完全不同。SFTP 是 SSH 的一个 subsystem,跑在 TCP 22 的 SSH 加密通道内,单端口、防火墙友好;FTPS 是 FTP + TLS,仍是 FTP 的双通道(控制 21 + 数据端口)模型,NAT/防火墙配置麻烦。

Q12:抓包能看到 SSH 里传了什么命令吗? A:SSH_MSG_NEWKEYS 之后全部加密,看不到内容。但仍可从包长与时序做侧信道推断(交互式击键产生规律小包,可辅助判断输入长度),以及看到明文的版本串与算法协商清单。