Linux 服务器 SSH 安全加固实战:密钥登录、双因素认证与 fail2ban 完整防线

只要服务器公网 IP 一暴露,SSH 的 22 端口就会在几分钟内被全球的扫描器盯上。查看 journalctl -u ssh 或者 lastb,几乎每天都有几百上千条失败的登录尝试,密码简单一点,被爆破只是时间问题。这篇文章把一套完整的 SSH 加固方案从头到尾讲一遍:先看现状,再做密钥登录、收紧 sshd 配置、上双因素认证,最后用 fail2ban 兜底,层层设防。

一、先看看你的服务器正在经历什么

动手之前,先了解一下攻击者有多勤奋。执行下面两条命令,看看最近失败的登录记录:

# 查看最近的错误登录尝试
lastb | head -30

# 查看 SSH 服务的登录日志
journalctl -u ssh --since "24 hours ago" | grep "Failed password" | wc -l

如果失败次数上千,说明你的 IP 已经被爆破程序盯上了。不用慌,这正是下面这套方案要解决的问题。另外建议先检查一下有没有已经被攻破的迹象:who 看当前登录用户、cat /root/.ssh/authorized_keys 看有没有陌生的公钥、crontab -l 看有没有可疑的计划任务。

二、第一步:配置密钥登录,替代密码认证

密钥登录的原理是非对称加密:私钥留在本地,公钥放到服务器。爆破程序猜不出私钥,安全性比任何强密码都高。先在本地电脑生成密钥对:

ssh-keygen -t ed25519 -C "my-server-key" -f ~/.ssh/id_ed25519

推荐用 ed25519 算法,密钥短、速度快、安全性高,比 RSA 2048 更推荐。生成后把公钥安装到服务器:

ssh-copy-id -i ~/.ssh/id_ed25519.pub root@你的服务器IP

ssh-copy-id 会自动把公钥追加到服务器的 ~/.ssh/authorized_keys。如果你用的是 Windows,可以用 type $env:USERPROFILE\.ssh\id_ed25519.pub | ssh user@ip "cat >> ~/.ssh/authorized_keys" 达到同样效果。这里有一个关键坑:服务器上 ~/.ssh 目录权限必须是 700,authorized_keys 文件必须是 600,权限过宽 SSH 会直接拒绝使用这个文件:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

装好之后,先不要关密码登录。开一个新的终端窗口,用密钥重新登录一次,确认能顺利连上、能 sudo,再继续下一步。很多人改完配置发现自己被关在门外,就是因为没有保留一个已建立的会话作为退路。

三、第二步:收紧 sshd_config,关掉危险选项

编辑 /etc/ssh/sshd_config,逐项检查下面这些配置。改完必须执行 sshd -t 验证语法,再 systemctl restart sshd 生效:

# 禁止 root 直接登录(用普通用户登录后再 su 或 sudo)
PermitRootLogin no

# 关闭密码认证,只允许密钥
PasswordAuthentication no
PubkeyAuthentication yes

# 限制登录尝试次数和超时
MaxAuthTries 3
LoginGraceTime 30

# 只允许指定用户登录,白名单模式
AllowUsers zhangsan

# 显式指定协议版本
Protocol 2

各项说明:PermitRootLogin no 是重中之重,root 是爆破程序的第一目标,禁掉之后攻击面骤减;PasswordAuthentication no 要在密钥登录确认可用之后再开,顺序不能反;AllowUsers 是白名单,只放行你常用的用户名,其他人连尝试的机会都没有。关于修改端口(比如把 22 改成 2222),我的建议是:配合防火墙做可以,但别把它当成安全手段——扫描器是全端口扫描,改端口只能挡掉一部分脚本小子,真正的安全靠的是密钥认证和 fail2ban。

改完配置后记得同步防火墙规则。以 ufw 为例:

ufw allow from 你的固定IP to any port 22 proto tcp
ufw enable

如果家里是动态 IP,可以把 IP 换成公司出口或常用 VPN 的网段,实在不行再放行整个公网,但一定要配合 fail2ban。

四、第三步:加上双因素认证,密钥丢了也不怕

密钥文件本身也可能被盗(比如电脑中木马)。加上 TOTP 双因素认证之后,即使私钥泄露,攻击者没有手机上的动态验证码也登不进去。以 Debian/Ubuntu 为例:

apt install libpam-google-authenticator
google-authenticator

运行 google-authenticator 会生成一个二维码和一个密钥,用手机上的身份验证器 App(Google Authenticator、Microsoft Authenticator、和风验证器都行)扫码绑定。然后把 PAM 配置加进 /etc/pam.d/sshd

# 放在文件最前面
auth required pam_google_authenticator.so

同时在 sshd_config 里开启挑战应答认证:

ChallengeResponseAuthentication yes
AuthenticationMethods publickey,keyboard-interactive

注意 AuthenticationMethods 用逗号分隔表示「必须全部通过」:先验证密钥,再验证动态码,缺一不可。这里最容易踩的坑是只改了 PAM 忘了改 sshd_config,结果验证码永远不弹出来。另外提醒一句,双因素认证会打断自动化脚本的登录,如果你有 rsync、git 拉取等免交互场景,要么给这些脚本单独配密钥,要么评估后选择性开启。

五、第四步:fail2ban 自动封禁暴力破解 IP

密钥+双因素已经让爆破基本失效,但日志里还是会积累大量无效尝试,fail2ban 的作用就是把这些 IP 自动拉黑,从源头减少骚扰。安装并配置:

apt install fail2ban
cat > /etc/fail2ban/jail.local <<'EOF'
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600
EOF
systemctl enable --now fail2ban

参数含义:maxretry 3 表示 10 分钟(findtime)内失败 3 次就封禁;bantime 3600 表示封 1 小时。用 fail2ban-client status sshd 查看当前封禁列表,被封的 IP 在 iptables -L -n | grep f2b 里也能看到。如果误封了自己,用 fail2ban-client set sshd unbanip 你的IP 解封。

注意:fail2ban 依赖防火墙规则生效,如果用云厂商的安全组,记得在安全组里放行 fail2ban 要操作的链;另外日志路径因发行版而异,Debian 系是 /var/log/auth.log,CentOS 系是 /var/log/secure,写错了 fail2ban 什么都监测不到,这是最常见的配置错误。

六、端口修改与云安全组:把攻击面再缩小一圈

虽然前面说过改端口不是安全手段,但配合防火墙把 SSH 端口从 22 改成高位端口(比如 22822),确实能让日志里的扫描尝试减少一大半——大多数脚本小子只会扫默认端口。修改分三步:

# 第一步:sshd_config 里改端口
Port 22822

# 第二步:防火墙放行新端口并拒绝 22
ufw allow 22822/tcp
ufw deny 22/tcp

# 第三步:重启前先验证语法,重启后务必保留当前会话
sshd -t && systemctl restart sshd

这里有一个极其重要的提醒:如果服务器在云厂商(阿里云、腾讯云、搬瓦工等)买了安全组,安全组规则和服务器内部防火墙是两层,必须同时放行新端口。很多人改完端口重启 SSH,发现连不上,就是因为只改了服务器内部,忘了改安全组,而安全组默认把新端口挡在外面。所以顺序应该是:先在安全组放行 22822,再改 sshd_config,最后重启。万一真的把自己锁在外面,云厂商控制台基本都提供 VNC 网页终端,可以从那里进去把配置改回来,这是最后的保命通道。

另外,无论是否改端口,都建议在云厂商控制台给安全组加上来源 IP 限制:只允许你常用的 IP 段访问 SSH 端口。家里宽带如果是动态 IP,可以退而求其次放行整个公网,但务必保留 fail2ban 兜底。

七、常见问题排查:登录被拒时按这个顺序查

加固过程中最痛苦的事就是突然登不进去了。遇到 Permission denied (publickey) 之类的问题,按下面的顺序逐项排查:

第一步,确认用的是不是正确的私钥:ssh -v user@ip 看详细输出,重点看 Offering public key 后面跟的指纹,和你本地 ssh-keygen -lf ~/.ssh/id_ed25519.pub 显示的指纹是否一致,不一致就是 SSH 客户端选错了密钥,用 -i 参数指定。第二步,确认服务器上 authorized_keys 的权限:目录 700、文件 600,权限过宽会被忽略,这是新手最常踩的坑。第三步,确认 sshd 配置没有互相矛盾:比如同时开了 PasswordAuthentication noAuthenticationMethods 且顺序写错,或者 AllowUsers 里的用户名和实际登录名大小写不一致。第四步,看日志:journalctl -u ssh -f 实时看认证日志,Failed passwordPermission denied 的区别能直接告诉你问题是出在密码阶段还是密钥阶段。

最后建议在服务器上常备一条「逃生通道」:保留一个 screentmux 会话,改任何可能影响登录的配置前,先在这个会话里执行,配置错了也能马上改回来,不用提心吊胆地等连接超时。

八、最后:养成三个好习惯

加固完成不代表一劳永逸,日常维护还有三件事:第一,给密钥做注释并定期轮换,员工离职或电脑更换时及时从 authorized_keys 里移除旧公钥;第二,关注系统安全更新,apt update && apt upgrade 至少每月一次,OpenSSH 本身也出过严重漏洞;第三,定期翻一翻 last 和认证日志,对异常登录保持敏感。

这套组合拳(密钥登录 + 禁 root + 双因素 + fail2ban)是我给所有服务器上线的标准流程,整套配置下来不到半小时,却能把 SSH 被攻破的概率降到接近于零。安全没有银弹,但把每一层都做好,攻击者自然会去找更软的柿子。

Last modification:August 24th, 2026 at 08:12 am

Leave a Comment