第一节 SSH 简介
1.1 什么是 SSH
SSH 为 Secure Shell 的缩写,是一种用于远程登录和文件传输的加密协议。它工作在应用层,基于传输层 TCP(默认 22 端口)。
只要记住一句:SSH 把"明文传输的 telnet"变成了"加密传输"。
1.2 基础信息
| 项目 | 内容 |
|---|---|
| 默认端口 | **22** |
| Linux 守护进程 | **`sshd`** |
| 安装服务 | **OpenSSH** |
| 服务端主程序 | `/usr/sbin/sshd` |
| 客户端主程序 | `/usr/bin/ssh` |
| 服务端配置 | `/etc/ssh/sshd_config` |
| 客户端配置 | `/etc/ssh/ssh_config` |
# 确认是否安装
rpm -qa | grep openssh
dnf install -y openssh-server openssh-clients
# 确认服务状态
systemctl status sshd
ss -lntp | grep :22
第二节 SSH 原理
2.1 对称加密
采用单钥密码系统,同一个密钥既用于加密也用于解密。
- 优点:快,适合加密大量数据
- 缺点:密钥怎么安全地交给对方?这就是"密钥分发问题"
- 代表算法:AES、ChaCha20
2.2 非对称加密
又名"公开密钥加密算法",需要一对密钥:
- 公钥(public key):可以公开
- 私钥(private key):只有自己持有
核心特性:
公钥加密 → 只有私钥能解
私钥签名 → 只有公钥能验
- 优点:解决了密钥分发问题
- 缺点:慢,比对称加密慢几个数量级
- 代表算法:RSA、ECDSA、Ed25519
2.3 SSH 为什么两种都用(★ 核心)
很多人背了两种算法,却说不清 SSH 到底用哪种。答案是:两种都用,各管一段。
| 阶段 | 用什么 | 为什么 |
|---|---|---|
| **建立连接时** | 非对称加密 | 安全地协商出会话密钥,不需要提前共享密码 |
| **传输数据时** | **对称加密** | 速度快,适合大流量 |
一句话:
非对称负责"安全地把钥匙交给你",对称负责"拿到钥匙后高效地传数据"。
2.4 完整的连接建立过程
① TCP 三次握手,连上 22 端口
② 协议版本协商
客户端:SSH-2.0-OpenSSH_8.0
服务端:SSH-2.0-OpenSSH_8.7
③ 算法协商
双方各自列出支持的加密算法,选出一个都支持的
④ 密钥交换(KEX)
通过 Diffie-Hellman 算法,双方各自算出【同一个会话密钥】
★ 注意:这个密钥从来没有在网络上传输过
⑤ 服务端出示主机公钥
客户端校验:这个公钥和我记过的一致吗?(known_hosts)
★ 这一步防的是"中间人攻击"
⑥ 用户身份认证(二选一)
· 密码认证:在【已加密的通道】里传密码
· 公钥认证:客户端用私钥签名,服务端用公钥验签
⑦ 认证通过,建立会话
之后所有数据都用【对称加密】传输
2.5 两种用户认证方式
| **密码认证** | **公钥认证** | |
|---|---|---|
| 原理 | 把密码放进加密通道里传 | 客户端用私钥签名,服务端用公钥验签 |
| 私钥会传输吗 | — | **不会**,只传签名 |
| 安全性 | 中(可能被暴力破解) | 高 |
| 便利性 | 要输密码 | 免密登录 |
| 生产推荐 | 关掉 | **推荐** |
第三节 SSH 配置文件
3.1 服务端配置:/etc/ssh/sshd_config
| 参数 | 常见值 | 说明 |
|---|---|---|
| `Port` | `22` | 监听端口 |
| `ListenAddress` | `0.0.0.0` | 监听的 IP |
| `HostKey` | `/etc/ssh/ssh_host_ed25519_key` | 服务端主机私钥位置 |
| `LogLevel` | `INFO` | 日志等级 |
| `SyslogFacility` | `AUTH` | 日志记录 SSH 登录情况 |
| `GSSAPIAuthentication` | `yes` | GSSAPI(Kerberos)认证 |
| `PermitRootLogin` | `yes` / `no` | 是否允许 root 直接登录 |
| `PubkeyAuthentication` | `yes` | 是否启用公钥认证 |
| `AuthorizedKeysFile` | `.ssh/authorized_keys` | 公钥保存位置(相对用户家目录) |
| `PasswordAuthentication` | `yes` / `no` | 是否允许密码认证 |
| `PermitEmptyPasswords` | `no` | 是否允许空密码 |
| `UsePAM` | `yes` | 是否使用 PAM 做认证/会话管理 |
| `MaxAuthTries` | `6` | 最大认证尝试次数 |
关于 GSSAPIAuthentication(常见坑)
在没有 Kerberos/DNS 的实验环境里,这个选项会让登录卡好几秒。
# 服务端
GSSAPIAuthentication no # /etc/ssh/sshd_config
# 客户端
GSSAPIAuthentication no # /etc/ssh/ssh_config
两个文件里都有这一项,两边都关掉才彻底不卡。
关于已过时的参数
| 旧参数 | 说明 |
|---|---|
| `Protocol 2` | OpenSSH 7.6+ 已删除,不用再写 |
| `ServerKeyBits 1024` | 已移除,且 1024 位过弱 |
| `ssh_host_dsa_key` | DSA 在 7.0+ 默认禁用,用 ed25519 或 rsa |
改完配置必须重启服务:
sshd -t # ★ 先检查语法,避免把自己锁在外面
systemctl restart sshd
3.2 客户端配置:/etc/ssh/ssh_config
客户端配置管的是"我怎么连别人",常见内容:
Host myserver
HostName 192.168.44.2
User root
Port 2222
IdentityFile ~/.ssh/id_ed25519
配好之后,直接 ssh myserver 就能连。
| 参数 | 作用 |
|---|---|
| `Host` | 别名,供 `ssh 别名` 使用 |
| `HostName` | 真实 IP 或域名 |
| `User` | 默认登录用户名 |
| `Port` | 默认端口 |
| `IdentityFile` | 指定私钥文件 |
| `StrictHostKeyChecking` | 是否严格校验主机公钥(实验环境可设 `no`,生产**不要**) |
| `ServerAliveInterval` | 多少秒发一次心跳,防断线 |
| `TCPKeepAlive` | 是否用 TCP 层保活 |
生产建议:加
ServerAliveInterval 60,避免长时间不操作被防火墙断开。
3.3 认证相关文件一览
| 文件 | 位置 | 作用 |
|---|---|---|
| 私钥 | `~/.ssh/id_ed25519` | 自己的私钥,**权限必须 600** |
| 公钥 | `~/.ssh/id_ed25519.pub` | 自己的公钥,可以公开 |
| 授权公钥 | `~/.ssh/authorized_keys` | 允许登录这台机器的公钥列表 |
| 已知主机 | `~/.ssh/known_hosts` | 记录连过的主机公钥 |
| 服务端主机密钥 | `/etc/ssh/ssh_host_*` | 服务端身份,**重装后会变** |
第四节 常用 SSH 命令
4.1 ssh 远程登录
ssh 用户名@IP
ssh root@192.168.44.2
ssh -p 2222 root@192.168.44.2 # 指定端口
ssh -i ~/.ssh/id_ed25519 root@IP # 指定私钥
客户端是通用的:Windows(PowerShell/termius)、macOS 终端、Linux 都能用同样的命令连 Linux 服务器。
4.2 常用参数
| 参数 | 作用 |
|---|---|
| `-p` | 指定端口 |
| `-i` | 指定私钥文件 |
| `-v` / `-vv` / `-vvv` | 调试模式,**卡在哪一步一目了然** |
| `-o` | 临时指定配置项,如 `-o StrictHostKeyChecking=no` |
| `-N` | 不执行远程命令(只做转发) |
| `-f` | 后台运行 |
| `-T` | 不分配伪终端 |
| `-L` / `-R` / `-D` | 端口转发 |
4.3 scp 文件传输
# 下载:远程 → 本地
scp root@192.168.44.2:/root/test.txt .
scp -r root@192.168.44.2:/root/logs ./logs
# 上传:本地 → 远程
scp /root/123 root@192.168.44.2:/root/
scp -r /root/123 root@192.168.44.2:/root/
例子逐项拆解:
scp -r localfile.txt username@192.168.0.1:/home/username/
| 部分 | 含义 |
|---|---|
| `scp` | 命令 |
| `-r` | 递归(传目录) |
| `localfile.txt` | 本地文件路径 |
| `username` | 服务器账号 |
| `192.168.0.1` | 服务器 IP |
| `/home/username/` | 目标目录 |
版本提醒:OpenSSH 9.0 起,
scp默认改用 SFTP 协议传输。连很老的服务器如果报错,可以加-O强制用旧协议。
大文件建议用
rsync:支持断点续传和增量同步,比scp更适合重复同步场景。
4.4 sftp 交互式传输
sftp root@192.168.4.2
| 命令 | 作用 |
|---|---|
| `ls` | 查看**服务器端**文件 |
| `cd` | 切换**服务器端**目录 |
| `pwd` | 显示服务器端当前目录 |
| `lls` | 查看**本地**文件 |
| `lcd` | 切换**本地**目录 |
| `get` | 下载 |
| `put` | 上传 |
| `mkdir` / `rm` | 在服务器端建目录 / 删文件 |
| `bye` / `exit` | 退出 |
记忆法:带
l前缀的是本地(local),不带的是远端。
4.5 免密登录(公钥认证)
第一步:生成密钥对
ssh-keygen -t ed25519 -C "your_email@example.com"
# 一路回车即可,默认保存到 ~/.ssh/
第二步:把公钥传到目标机器
ssh-copy-id root@192.168.44.2
# 或者手动:ssh root@IP "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys" < ~/.ssh/id_ed25519.pub
第三步:验证
ssh root@192.168.44.2 # 不再提示输入密码
★ 权限必须正确,否则免密一定失败
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_ed25519
| 路径 | 要求权限 |
|---|---|
| `~/.ssh` | `700` |
| `~/.ssh/authorized_keys` | `600` |
| `~/.ssh/id_*`(私钥) | `600` |
| 用户家目录 | **不能对组或其他用户可写** |
报错
Authentication refused: bad ownership or modes就是这个原因。
4.6 known_hosts 与首次连接
第一次连接某台主机时,会看到:
The authenticity of host '192.168.44.2' can't be established.
ED25519 key fingerprint is SHA256:xxxxxxxx...
Are you sure you want to continue connecting (yes/no)?
输入 yes 后,对方的主机公钥会被写入 ~/.ssh/known_hosts。
重装系统或换机器后,会报这个错:
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
不是被攻击,而是主机密钥变了。清除旧记录:
ssh-keygen -R 192.168.44.2
4.7 端口转发(运维高频)
| 类型 | 命令 | 场景 |
|---|---|---|
| **本地转发** | `ssh -L 8080:127.0.0.1:80 user@跳板机` | 通过跳板访问内网服务 |
| **远程转发** | `ssh -R 8080:127.0.0.1:80 user@公网机` | 把内网服务暴露到公网 |
| **动态转发** | `ssh -D 1080 user@跳板机` | 建一个 SOCKS 代理 |
# 本地转发:访问本机 8080,等于访问跳板机能看到的 127.0.0.1:80
ssh -N -f -L 8080:127.0.0.1:80 root@192.168.44.2
-N:不执行远程命令-f:后台运行
第五节 运维必备
5.1 服务管理
systemctl status sshd
systemctl restart sshd
ss -lntp | grep :22
journalctl -u sshd -f
tail -f /var/log/secure # Rocky/CentOS 的 SSH 日志
5.2 修改端口的完整步骤(★ 最容易漏 SELinux)
# 1) 改配置
vim /etc/ssh/sshd_config
Port 2222
# 2) 防火墙放行
firewall-cmd --permanent --add-port=2222/tcp
firewall-cmd --reload
# 3) SELinux 放行(Rocky/CentOS 必做!)
semanage port -a -t ssh_port_t -p tcp 2222
# 4) 检查语法再重启
sshd -t
systemctl restart sshd
# 5) 新开一个窗口验证,确认能连再关掉旧连接
ssh -p 2222 root@IP
semanage不是默认安装的:dnf install -y policycoreutils-python-utils漏了这步的表现是:端口在监听、防火墙也放行了,就是连不上。
5.3 连接不上怎么排查
# 客户端:看卡在哪一步
ssh -vvv root@192.168.44.2
# 服务端:服务在跑吗
systemctl status sshd
ss -lntp | grep sshd
# 服务端:日志说了什么
journalctl -u sshd --since "10 minutes ago"
tail -50 /var/log/secure
# 网络层排查
ping 192.168.44.2
nc -vz 192.168.44.2 22
| 现象 | 大概率原因 |
|---|---|
| `Connection refused` | sshd 没起 / 端口不对 / 防火墙 REJECT |
| `Connection timed out` | 防火墙 DROP / 网络不通 |
| `Permission denied (publickey)` | 公钥没传对 / 权限不对 |
| 卡在 `pledge` 或几秒无响应 | GSSAPI 没关 / DNS 反解慢 |
| `REMOTE HOST IDENTIFICATION HAS CHANGED` | 主机密钥变了,`ssh-keygen -R` |
5.4 安全加固清单
| 加固项 | 配置 | 说明 |
|---|---|---|
| 禁用 root 直接登录 | `PermitRootLogin no` | 用普通用户登录后 `sudo` |
| 禁用密码认证 | `PasswordAuthentication no` | 只留公钥登录 |
| 限制尝试次数 | `MaxAuthTries 3` | 降低暴力破解空间 |
| 限制可登录用户 | `AllowUsers ops` | 白名单 |
| 空闲超时 | `ClientAliveInterval 300` + `ClientAliveCountMax 2` | 10 分钟无操作断开 |
| 改端口 | `Port 2222` | 只减少扫描噪音,**不是真正的安全措施** |
| 防暴力破解 | fail2ban | 多次失败自动封 IP |
面试点:"改端口能提升安全性吗?" → 只能减少自动化扫描的噪音,扫描器照样能全端口扫出来。真正的安全靠密钥认证 + 禁用 root + 最小权限。
第六节 易错点
- 客户端配置和服务端配置不是一回事:
PermitRootLogin、PasswordAuthentication这些只能写在sshd_config。 - 改完
sshd_config一定要systemctl restart sshd,而且要先sshd -t检查语法,否则可能把自己锁在外面。 - 改端口必须同时处理防火墙和 SELinux,漏一个就连不上。
- 公钥免密登录失败,九成是权限问题(
.ssh700、authorized_keys600)。 known_hosts里记录的是主机公钥,不是你的公钥;重装系统后必然变化。scp -r的-r是递归,传目录必须加。- 私钥绝对不能外传,
authorized_keys里放的永远是.pub文件。 - GSSAPI 没关会导致登录慢,服务端和客户端都要检查。
第七节 SSH 连接工具
| 工具 | 平台 | 说明 |
|---|---|---|
| **PuTTY** | Windows | 老牌免费工具,支持 SSH、Telnet、串口 |
| **SecureCRT** | Windows / macOS | 商业软件,多标签、会话管理强 |
| **Xshell** | Windows | 商业软件,国内使用广泛 |
| **Mac 自带终端** | macOS | 系统自带,直接用 `ssh` 命令 |
第八节 密钥对登录
本节和 4.5 是同一件事。 4.5 用
ssh-keygen -t ed25519+ssh-copy-id,更短更稳;本节是传统的手工步骤,对照着看即可。
密钥对验证:既安全又方便。
步骤 1:生成并上传公钥
Client 客户端:
ssh-keygen -t rsa
Server 服务端:把公钥上传到服务器
cat id_rsa.pub >> /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys
步骤 2:修改服务端 SSH 配置文件
vim /etc/ssh/sshd_config
PubkeyAuthentication yes # 是否使用公钥验证
AuthorizedKeysFile .ssh/authorized_keys # 公钥保存位置
PasswordAuthentication no # 禁止使用密码验证登录
步骤 3:重启 SSH 服务
systemctl restart sshd
这篇内容从底层原理到配置、排障与安全加固,覆盖运维日常最高频的 SSH 场景。易错点与加固清单尤其实用,适合 Linux 运维入门者和面试复习对照查阅。