结论: 服务器 SSH 安全配置的六项核心是:改 ed25519 密钥登录、禁止 root 直登(PermitRootLogin no)、关闭密码认证(PasswordAuthentication no)、用 AllowUsers 限定可登录账户、收紧 MaxAuthTries 与 LoginGraceTime、每次修改用 sshd -t 校验后再重载。做完这六项,SSH 通道的风险可降低九成以上。
SSH(Secure Shell)是几乎所有 Linux 服务器的唯一管理入口,也因此成为攻击者的首要目标。绝大多数服务器沦陷事件并非源于什么高深漏洞,而是 SSH 配置不当:允许 root 直接用密码登录、密码认证长期开放、端口对全世界开放、账户没有白名单限制。本节按照"改前备份 → 分片配置 → 语法校验 → 保留会话验证"的标准流程,把 sshd 配置一次做对。
sshd_config 关键参数怎么配?
sshd_config是 OpenSSH 服务端的主配置文件,路径为/etc/ssh/sshd_config。现代发行版(Ubuntu 20.04+、RHEL 8+)的主文件顶部都包含Include /etc/ssh/sshd_config.d/*.conf,因此推荐把自定义配置写成该目录下的独立文件,既避免升级冲突,也便于版本管理。
下表列出生产环境必须关注的参数及其推荐值:
| 参数 | 推荐值 | 作用 | 风险提示 |
|---|---|---|---|
Port | 22 或自定义高位端口 | 监听端口 | 改后必须同步放通防火墙与安全组 |
AddressFamily | inet | 只监听 IPv4 | 需要 IPv6 时设为 any |
ListenAddress | 内网 IP | 只监听指定网卡 | 配置错误会导致 SSH 不可达 |
PermitRootLogin | no | 禁止 root 直接登录 | 必须先有可用的 sudo 账户 |
PasswordAuthentication | no | 禁用密码认证 | 必须先配好密钥,否则失联 |
PubkeyAuthentication | yes | 启用公钥认证 | 保持开启 |
PermitEmptyPasswords | no | 禁止空密码 | 始终保持 no |
MaxAuthTries | 3 | 单连接最大认证尝试次数 | 超过即断开连接 |
LoginGraceTime | 30(秒) | 登录宽限期,超时断开 | 太短会影响慢网络下的密钥协商 |
AllowUsers | opsadmin deploy@10.0.0.0/8 | 账户/IP 白名单 | 漏写自己会被永久拒绝 |
AllowGroups | sshusers | 用户组白名单 | 与 AllowUsers 同时存在时取并集限制的交叉 |
X11Forwarding | no | 关闭 X11 转发 | 不需要图形界面应关闭 |
AllowTcpForwarding | no | 关闭端口转发 | 需要跳板机/隧道时改为 yes |
ClientAliveInterval | 300 | 每 300 秒发一次保活包 | 配合下一条使用 |
ClientAliveCountMax | 3 | 连续 3 次无响应断开 | 300×3 ≈ 15 分钟空闲超时 |
Protocol | 2 | 只支持 SSH2 | SSH1 已废弃且不安全 |
一份可直接落地的配置分片
# 备份原始配置,改坏了能立刻回滚
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d)
cat > /etc/ssh/sshd_config.d/00-hardening.conf <<'EOF'
# ===== 认证方式 =====
PubkeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no
AuthenticationMethods publickey
# ===== 账户限制 =====
PermitRootLogin no
AllowUsers opsadmin deploy@10.0.0.0/8
MaxAuthTries 3
MaxSessions 5
LoginGraceTime 30
# ===== 转发与隧道(按需开启)=====
X11Forwarding no
AllowTcpForwarding no
AllowAgentForwarding no
GatewayPorts no
# ===== 连接保活 =====
TCPKeepAlive yes
ClientAliveInterval 300
ClientAliveCountMax 3
# ===== 协议与算法收紧 =====
HostKey /etc/ssh/ssh_host_ed25519_key
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
EOF
chmod 600 /etc/ssh/sshd_config.d/00-hardening.conf修改后必须做语法校验,这是避免失联的关键一步:
# 校验配置文件语法(-t = test),无任何输出表示通过
sshd -t
# 想查看最终生效的完整配置(含默认值),用大写 -T
sshd -T | grep -E "permitrootlogin|passwordauthentication|maxauthtries|allowusers"
# 确认无误后重载(不是 restart,reload 不会断开现有连接,更安全)
systemctl reload sshd
# RHEL 系服务名同为 sshd: systemctl reload sshd密钥登录怎么配?为什么选 ed25519
SSH 密钥登录用非对称加密替代密码传输。目前主流算法有三种,推荐优先级明确:
- ed25519(推荐):椭圆曲线算法,密钥短(公钥仅 68 字符)、速度快、抗侧信道,OpenSSH 6.5+ 支持。
- ecdsa:同为椭圆曲线,但曲线参数由 NIST 制定,行业信任度略低。
- rsa:兼容性最好,但需 3072 或 4096 位才能达到同等强度,生成慢、验签慢。老设备(如部分交换机)不得不用时才考虑。
# 本地生成 ed25519 密钥对(-a 指定 KDF 轮数,提高私钥文件自身的抗爆破能力)
ssh-keygen -t ed25519 -a 100 -C "zhang.san@company-2026" -f ~/.ssh/id_ed25519_company
# 方式一:自动推送公钥到服务器(推荐)
ssh-copy-id -i ~/.ssh/id_ed25519_company.pub opsadmin@203.0.113.10
# 方式二:手动追加(服务器侧)
cat >> ~/.ssh/authorized_keys <<'EOF'
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIExamplePublicKeyContentDoNotUseInProduction zhang.san@company-2026
EOF
chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys
chown -R opsadmin:opsadmin ~/.ssh权限是密钥登录失败最常见的原因:~/.ssh 必须是 700,authorized_keys 必须是 600,家目录不能被群组或其他用户可写,否则 sshd 出于安全考虑会直接忽略公钥并在日志中留下 Authentication refused: bad ownership or modes。
本地客户端侧的推荐配置(~/.ssh/config):
Host prod-web
HostName 203.0.113.10
Port 23456
User opsadmin
IdentityFile ~/.ssh/id_ed25519_company
IdentitiesOnly yes
# 防止网络抖动导致频繁断线
ServerAliveInterval 60
ServerAliveCountMax 3
# 跳板机场景启用连接复用,后续连接秒开
ControlMaster auto
ControlPath ~/.ssh/cm-%r@%h:%p
ControlPersist 4h配好之后 ssh prod-web 即可直连,无需每次敲完整参数。
如何做到"改了不翻车":安全变更流程
SSH 配置是极少数"改错就永久失联"的操作之一。请严格按以下流程执行:
- 第一步:确认你拥有备用登录通道——云厂商控制台的 VNC/串口/救援模式,或第二个管理员账户的物理访问。
- 第二步:用
cp备份原配置,出错可立刻还原。 - 第三步:保持当前 SSH 会话不要断开,在新窗口里测试新配置。
- 第四步:执行
sshd -t语法校验,无输出才继续。 - 第五步:
systemctl reload sshd,然后新开窗口用新方式登录验证。 - 第六步:验证成功后,再关闭旧的保底会话。
# 万一被锁在外面也没有 VNC:可用 systemd 回滚(需要能进 VNC/串口)
mv /etc/ssh/sshd_config.d/00-hardening.conf /root/00-hardening.conf.disabled
systemctl restart sshd
# 排查登录失败的实时日志(另开窗口)
journalctl -u sshd -f
# 或 Debian 系: tail -f /var/log/auth.log更多登录类故障的定位方法参见 服务器SSH连接不上怎么办 与 服务器怎么远程连接。
进阶:SSH 防断开、跳板与证书认证
长时间运行的任务是"SSH 断线导致命令中断"的高发场景。除服务端 ClientAliveInterval 外,还可以用终端复用工具彻底解决:
# 用 tmux 建立可恢复会话,断网后重连即可恢复现场
tmux new -s ops
# 断开(不是退出):Ctrl + b,然后按 d
# 重新接入: tmux attach -t ops
# 单次长任务也可直接用 nohup + setsid
setsid nohup rsync -aP /data/ backup:/data/ > /tmp/rsync.log 2>&1 &更进阶的做法是使用 SSH 证书认证(SSH Certificate Authority):用一把 CA 私钥签发带有效期的用户证书,员工离职只需吊销证书或到期自动失效,无需逐台机器增删 authorized_keys。
# 生成 SSH CA(离线保管私钥)
ssh-keygen -t ed25519 -f /etc/ssh/ca_key -C "company-ssh-ca"
# CA 签发用户公钥,有效期 8 小时(-z 指定序列号便于吊销)
ssh-keygen -s /etc/ssh/ca_key -I zhangsan -n opsadmin -V +8h id_ed25519_company.pub
# 服务端信任该 CA
cat >> /etc/ssh/sshd_config.d/10-ca.conf <<'EOF'
TrustedUserCAKeys /etc/ssh/ca_key.pub
EOF
sshd -t && systemctl reload sshd加固后怎么验证效果与持续审计?
结论:配置改完不算结束,要用「外部扫描 → 日志审计 → 定期复核」三步闭环验证。否则很容易出现"配置文件写对了,但被 Include 顺序覆盖""新开的账户绕过了 AllowUsers"这类假加固。
# 1. 外部视角验证:从另一台机器确认服务器只接受预期的认证方式
ssh -v -o PreferredAuthentications=password opsadmin@203.0.113.10 2>&1 | grep -i "permission denied"
nmap --script ssh2-enum-algos -p 22 203.0.113.10
# 2. 统计失败登录来源,判断是否需要接入 fail2ban
grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -nr | head -20
# 3. 复核最终生效配置,防止被后续 Include 覆盖
sshd -T | grep -E "^(permitrootlogin|passwordauthentication|allowusers|maxauthtries)"审计要点:每周看一次失败登录的来源 IP 排行,连续出现的地址直接写进防火墙黑名单;每季度复核一次 authorized_keys,清理离职人员的公钥;sudo 提权日志统一发往远端日志服务器,避免本机被入侵后日志被一并抹除。修改配置后建议保留一份基线快照(把 sshd -T 的输出存档),下次变更时用 diff 对比,能快速定位是哪次改动引入了问题。
常见误区 / 排错提示
AllowUsers写漏了自己的账户,reload 后所有人都登不上。 修改前先确认AllowUsers列表中包含至少一个当前可用账户,建议用AllowGroups+ 用户组管理,比逐个账户更不容易遗漏。sshd -t没报错但配置没生效。 注意参数重复定义时第一次出现的值优先;Include 的顺序按字母序加载,00-前缀的文件会被99-覆盖,因此关键限制项应放在编号更大的文件中。- 配了密钥仍然提示输入密码。 90% 是权限问题:检查
~/.ssh是否为 700、authorized_keys是否为 600、家目录是否 755 且属主正确,再看journalctl -u sshd的具体报错。 - 把
LoginGraceTime设为 0 以为能提升安全。 0 表示永久不超时,反而会让半开连接占满MaxStartups,正确做法是给一个 20~60 秒的短窗口。 AllowTcpForwarding no导致内网穿透和 VSCode Remote 失效。 需要远程开发或跳板时,应针对特定用户用Match User deploy段落单独放行。- 用
systemctl restart sshd而非reload。 restart 会断开所有现有连接,reload 平滑重载,生产环境一律用 reload。
常见问题(FAQ)
SSH 默认端口一定要改吗?
不一定要改,把 22 改成高位端口属于"隐蔽安全",能显著减少日志噪音但挡不住定向扫描。优先级顺序是:先配好密钥 + 禁用密码 + 禁止 root 直登,再考虑改端口。若决定修改,务必同步放通云安全组与系统防火墙,否则会直接失联。
root 不能登录了,怎么执行需要最高权限的操作?
正确做法是创建一个普通账户并加入 wheel/sudo 组,登录后用 sudo -i 或 sudo <命令> 提权。这样每个提权操作都会留下带用户名的日志,出现安全事件时可精确定位到人,这是等保合规的基本要求。
多人共用一台服务器,密钥怎么管理才不乱?
禁用"所有人共享一把私钥",改为每人提交自己的公钥,写入 ~/.ssh/authorized_keys 时在末尾追加 user@email 注释以便区分。规模超过 5 人建议引入 SSH CA 签发短期证书或堡垒机方案,做到"人走权销"。
修改 sshd_config 后无法登录,也没有控制台怎么办?
若还有已建立的会话,立即用它回滚配置;若会话已断,只能通过云厂商的 VNC、串口控制台或救援模式挂载磁盘修改。因此修改前保持一个不断开的会话是最廉价也最有效的保险手段。
ClientAliveInterval 设多少合适?
推荐服务端 ClientAliveInterval 300 + ClientAliveCountMax 3,即约 15 分钟无响应才断开,既能回收僵死连接又不影响正常使用。判断依据是网络质量与空闲容忍时间:内网或专线设 300 足够;NAT 网关、移动热点通常在几十秒到几分钟就回收空闲映射,此时应缩短到 60 并把 CountMax 调到 3。注意这是服务端主动探测,与客户端 ServerAliveInterval 二选一配置即可。
企业QQ咨询




