5月28日 02:10

如何进行 SSH 安全加固?有哪些最佳实践和安全配置建议?

SSH 安全加固是运维和后端面试中的高频考点,也是生产环境必须落地的安全措施。一次配置不当的 SSH 服务,可能让整个服务器暴露在暴力破解和未授权访问的风险之下。本文从认证、网络、加密、密钥管理、监控五个层面系统讲解 SSH 安全加固方案。

核心原则:最小权限 + 纵深防御

SSH 安全加固不是单一配置的修改,而是从多个层面构建防线。核心思路:即使某一层被突破,还有下一层阻拦。没有任何一项配置能单独保证安全,只有组合使用才能形成有效防御体系。

认证层加固

禁用密码认证,仅允许密钥登录

密码认证是暴力破解的最大突破口。密钥认证从根本上消除了密码被猜解的风险——密钥空间足够大,暴力破解在计算上不可行。

bash
# /etc/ssh/sshd_config PasswordAuthentication no PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keys

密钥类型选择:优先 ED25519(更短、更快、更安全),RSA 至少 4096 位。

bash
# 推荐:ED25519 ssh-keygen -t ed25519 -C "user@company" # 兼容场景:RSA 4096 ssh-keygen -t rsa -b 4096 -C "user@company"

注意:ED25519 不支持 -b 参数指定密钥长度,它的密钥长度是固定的。原始文章中 ssh-keygen -t ed25519 -b 4096 的写法是错误的,-b 参数会被忽略。

禁止 root 直接登录

生产环境中,root 直接登录是高危行为。应先以普通用户登录,再通过 sudo 提权,这样所有操作都有审计记录,便于事后追溯。

bash
# /etc/ssh/sshd_config PermitRootLogin no

如果必须允许 root 登录(极少数场景),至少使用 PermitRootLogin prohibit-password,仅允许密钥认证。prohibit-passwordwithout-password 更明确,是 OpenSSH 7.0+ 的推荐写法。

限制可登录的用户和组

不要让系统上所有用户都能 SSH 登录,明确指定允许登录的白名单。

bash
# /etc/ssh/sshd_config AllowUsers admin deploy AllowGroups ssh-users

AllowUsersAllowGroups 是白名单机制,不在名单中的用户即使有密钥也无法登录。两者同时配置时取交集,即用户必须同时满足用户和组的限制。搭配 DenyUsers 使用时,deny 优先于 allow。

限制认证尝试次数和连接速率

暴力破解依赖大量快速尝试,限制速率可以直接阻断此类攻击。

bash
# /etc/ssh/sshd_config MaxAuthTries 3 MaxStartups 10:30:100 LoginGraceTime 60

MaxStartups 10:30:100 的含义:超过 10 个未完成连接时,以 30% 概率拒绝新连接;超过 100 个时全部拒绝。这个参数是防止连接耗尽型攻击的关键配置。

网络层加固

修改默认端口

改端口不是安全措施,而是降低噪声的手段。自动化扫描工具通常只扫 22 端口,改端口后日志中的扫描噪音会大幅减少,便于发现真正有威胁的连接。

bash
# /etc/ssh/sshd_config Port 2222

修改后务必同步更新防火墙规则和安全组,否则会被自己挡在门外。建议在修改前先通过 console 或带外管理确认回退方案。

防火墙限制来源 IP

最有效的访问控制是只允许已知 IP 连接。

bash
# ufw 示例:仅允许办公网段 ufw allow from 10.0.1.0/24 to any port 2222 proto tcp ufw enable # iptables 示例 iptables -A INPUT -p tcp --dport 2222 -s 10.0.1.0/24 -j ACCEPT iptables -A INPUT -p tcp --dport 2222 -j DROP

如果来源 IP 不固定,可以配合 VPN 或跳板机使用,将 SSH 访问收敛到单一入口。云上环境建议通过安全组实现,比 iptables 更不易出错。

使用 fail2ban 自动封禁

fail2ban 通过分析日志自动封禁异常 IP,是对暴力破解的自动化防御。

bash
# /etc/fail2ban/jail.local [sshd] enabled = true port = 2222 maxretry = 3 bantime = 3600 findtime = 600

注意事项:maxretry 不宜设太小,否则合法用户输错一次密码就可能被封。生产环境建议配合 ignoreip 将管理网段加入白名单,避免误封。bantime 建议设为较长时间(如 86400),频繁攻击的 IP 没必要短时间解封。

配置连接超时

长时间空闲的 SSH 会话是安全隐患,终端可能被旁人操作。

bash
# /etc/ssh/sshd_config ClientAliveInterval 300 ClientAliveCountMax 2

300 秒(5 分钟)无操作发送一次心跳探测,连续 2 次无响应则断开。实际超时时间 = ClientAliveInterval * ClientAliveCountMax = 600 秒。根据业务场景调整:高频操作环境可以设短一些,长时间编译部署的环境适当延长。

加密层加固

使用强加密算法

默认配置可能包含已淘汰的弱算法(如 3des、arcfour)。显式指定安全算法列表,确保通信强度。

bash
# /etc/ssh/sshd_config KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group-exchange-sha256 Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com

可以用 ssh-audit 工具检测当前配置的加密强度:

bash
# 安装 pip3 install ssh-audit # 检测 ssh-audit server_ip

ssh-audit 会输出当前使用的密钥交换、加密、MAC 算法的安全等级,标记出需要替换的弱算法。

禁用不必要的功能

每多开一个功能就多一个攻击面。不需要的功能一律关闭。

bash
# /etc/ssh/sshd_config X11Forwarding no GatewayPorts no PermitTunnel no

AllowTcpForwarding 需要根据业务判断:如果需要端口转发(如数据库调试),保留 yes;否则设为 no。注意设为 no 并不能完全阻止端口转发,用户仍可通过 command= 方式间接实现,真正需要禁止时应配合 no-port-forwarding 在 authorized_keys 中限制。

密钥管理

为私钥设置密码短语

即使私钥文件泄露,没有密码短语也无法使用。这是密钥安全的最后一道防线。

bash
ssh-keygen -t ed25519 -C "user@company" # 在提示时输入强密码短语

已有密钥可以补设密码短语:

bash
ssh-keygen -p -f ~/.ssh/id_ed25519

配合 ssh-agent 使用,输入一次密码短语后,后续连接自动认证,不必每次都输入。

限制密钥用途

authorized_keys 中可以为每个密钥设置限制条件,实现精细化的访问控制。

bash
# ~/.ssh/authorized_keys # 限制只能执行特定命令 command="/usr/local/bin/backup.sh" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... # 限制来源 IP from="10.0.1.0/24" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... # 组合限制:来自特定 IP 且不能端口转发 from="10.0.1.0/24",no-port-forwarding ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...

这种机制特别适合 CI/CD 部署场景:为部署密钥绑定 command,即使密钥泄露,攻击者也只能执行指定命令。可用的限制选项还包括 no-pty(禁用交互式终端)、no-agent-forwarding(禁用 agent 转发)等。

定期轮换密钥

密钥应该像密码一样定期更换,尤其在人员离职时必须及时清理。

bash
# 生成新密钥 ssh-keygen -t ed25519 -f ~/.ssh/new_key -C "user@company" # 部署新公钥 ssh-copy-id -i ~/.ssh/new_key.pub user@server # 确认新密钥可用后再删除旧密钥 rm ~/.ssh/old_key ~/.ssh/old_key.pub

建议在密钥的 -C 注释中包含创建日期,方便追踪轮换周期。

多因素认证

SSH 证书替代传统密钥

大规模团队管理中,逐个分发密钥并维护 authorized_keys 效率极低。SSH 证书通过 CA 签发,自动过期,无需手动清理。

bash
# 生成 CA 密钥 ssh-keygen -t ed25519 -f /etc/ssh/ca_key # 签发用户证书(有效期 52 周) ssh-keygen -s /etc/ssh/ca_key -I user_id -n username -V +52w ~/.ssh/user_key.pub # 服务器端信任 CA # /etc/ssh/sshd_config TrustedUserCAKeys /etc/ssh/ca_key.pub

证书到期自动失效,人员离职只需不再签发新证书,无需逐台服务器删除公钥。这是 SSH 证书相比传统公钥的最大优势——集中化管理。Facebook(Meta)的基础设施就是大规模使用 SSH 证书的典型案例。

TOTP 双因素认证

在密钥认证基础上增加动态验证码,即使密钥泄露,没有验证码也无法登录。

bash
# 安装 Google Authenticator PAM 模块 apt-get install libpam-google-authenticator # 每个用户独立配置 google-authenticator # /etc/pam.d/sshd 添加 auth required pam_google_authenticator.so # /etc/ssh/sshd_config KbdInteractiveAuthentication yes

注意:OpenSSH 8.2+ 推荐使用 KbdInteractiveAuthentication 替代已弃用的 ChallengeResponseAuthentication。配置前确保有 console 访问作为回退手段,万一 PAM 配置出错不会锁死服务器。

监控与应急

日志监控

bash
# /etc/ssh/sshd_config LogLevel VERBOSE SyslogFacility AUTHPRIV

VERBOSE 级别会记录密钥指纹,便于追踪是哪个密钥登录的。INFO 级别不够详细,DEBUG 级别日志量过大影响性能,VERBOSE 是生产环境的平衡选择。

查看登录活动:

bash
# 最近成功登录 last -n 20 # 失败登录尝试 lastb -n 20 # 实时监控 tail -f /var/log/auth.log | grep sshd

登录告警

在关键服务器上配置登录通知,异常登录可以第一时间发现。

bash
# /etc/profile 或 ~/.bashrc if [ -n "$SSH_CLIENT" ]; then echo "SSH login: $(whoami) from $(echo $SSH_CLIENT | awk '{print $1}') at $(date)" | mail -s "SSH Login Alert: $(hostname)" admin@company.com fi

大规模环境建议接入集中化告警系统(如 Prometheus AlertManager),而不是依赖邮件通知。

入侵应急响应

一旦发现异常登录迹象,按以下步骤处置:

bash
# 1. 查看异常连接 ss -tnp | grep :2222 # 2. 紧急封禁可疑 IP iptables -A INPUT -s 可疑IP -j DROP # 3. 如果确认被入侵,立即切断 SSH 服务 systemctl stop sshd # 4. 修改配置后重启(先验证语法) sshd -t && systemctl start sshd

sshd -t 在重启前检查配置语法,避免配置错误导致无法远程连接。养成任何配置修改后都先执行 sshd -t 的习惯。

配置检查清单

每次加固后逐项确认:

  • 端口已改为非默认值,防火墙规则已同步更新
  • 密码认证已禁用,仅允许密钥登录
  • root 直接登录已禁止
  • 可登录用户已限制为白名单
  • 认证尝试次数已限制(MaxAuthTries <= 3)
  • 加密算法已更新为安全列表
  • fail2ban 已启用且白名单已配置
  • 空闲连接超时已设置
  • 日志级别设为 VERBOSE
  • 配置修改后已执行 sshd -t 验证语法
  • 已备份原配置文件(cp sshd_config sshd_config.bak)
  • 私钥已设置密码短语
  • 旧密钥和离职人员密钥已清理

常见误区

误区一:改了端口就安全了。 端口扫描工具可以遍历所有端口,改端口只是降低噪音,不能替代其他加固措施。

误区二:密钥认证就不需要 fail2ban 了。 fail2ban 还能防御探测行为和异常连接模式,两者互补而非替代。

误区三:加固一次就万事大吉。 SSH 软件需要定期更新,密钥需要轮换,日志需要审计。安全是持续过程,不是一次性操作。

误区四:配置越严格越安全。 过度加固可能导致运维不便甚至锁死自己。加固策略要根据实际场景权衡,始终确保有可恢复的手段(如 console 访问或带外管理)。

误区五:AllowTcpForwarding no 就能禁止端口转发。 用户仍可通过 command= 方式或 SSH 代理转发间接实现。真正需要禁止时应配合 authorized_keys 中的 no-port-forwarding 限制。

标签:SSH