服务器SSH安全怎么配置

结论: 服务器 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,因此推荐把自定义配置写成该目录下的独立文件,既避免升级冲突,也便于版本管理。

下表列出生产环境必须关注的参数及其推荐值:

参数推荐值作用风险提示
Port22 或自定义高位端口监听端口改后必须同步放通防火墙与安全组
AddressFamilyinet只监听 IPv4需要 IPv6 时设为 any
ListenAddress内网 IP只监听指定网卡配置错误会导致 SSH 不可达
PermitRootLoginno禁止 root 直接登录必须先有可用的 sudo 账户
PasswordAuthenticationno禁用密码认证必须先配好密钥,否则失联
PubkeyAuthenticationyes启用公钥认证保持开启
PermitEmptyPasswordsno禁止空密码始终保持 no
MaxAuthTries3单连接最大认证尝试次数超过即断开连接
LoginGraceTime30(秒)登录宽限期,超时断开太短会影响慢网络下的密钥协商
AllowUsersopsadmin deploy@10.0.0.0/8账户/IP 白名单漏写自己会被永久拒绝
AllowGroupssshusers用户组白名单与 AllowUsers 同时存在时取并集限制的交叉
X11Forwardingno关闭 X11 转发不需要图形界面应关闭
AllowTcpForwardingno关闭端口转发需要跳板机/隧道时改为 yes
ClientAliveInterval300每 300 秒发一次保活包配合下一条使用
ClientAliveCountMax3连续 3 次无响应断开300×3 ≈ 15 分钟空闲超时
Protocol2只支持 SSH2SSH1 已废弃且不安全

一份可直接落地的配置分片

bash
# 备份原始配置,改坏了能立刻回滚
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

修改后必须做语法校验,这是避免失联的关键一步:

bash
# 校验配置文件语法(-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 位才能达到同等强度,生成慢、验签慢。老设备(如部分交换机)不得不用时才考虑。
bash
# 本地生成 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):

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,然后新开窗口用新方式登录验证。
  • 第六步:验证成功后,再关闭旧的保底会话。
bash
# 万一被锁在外面也没有 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 外,还可以用终端复用工具彻底解决:

bash
# 用 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。

bash
# 生成 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"这类假加固。

bash
# 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 对比,能快速定位是哪次改动引入了问题。

常见误区 / 排错提示

  1. AllowUsers 写漏了自己的账户,reload 后所有人都登不上。 修改前先确认 AllowUsers 列表中包含至少一个当前可用账户,建议用 AllowGroups + 用户组管理,比逐个账户更不容易遗漏。
  2. sshd -t 没报错但配置没生效。 注意参数重复定义时第一次出现的值优先;Include 的顺序按字母序加载,00- 前缀的文件会被 99- 覆盖,因此关键限制项应放在编号更大的文件中。
  3. 配了密钥仍然提示输入密码。 90% 是权限问题:检查 ~/.ssh 是否为 700、authorized_keys 是否为 600、家目录是否 755 且属主正确,再看 journalctl -u sshd 的具体报错。
  4. 把 LoginGraceTime 设为 0 以为能提升安全。 0 表示永久不超时,反而会让半开连接占满 MaxStartups,正确做法是给一个 20~60 秒的短窗口。
  5. AllowTcpForwarding no 导致内网穿透和 VSCode Remote 失效。 需要远程开发或跳板时,应针对特定用户用 Match User deploy 段落单独放行。
  6. 用 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 二选一配置即可。