SSH 安全加固实战:密钥登录与 fail2ban 防暴力破解

几乎每一台暴露在公网上的 Linux 服务器,都在被暴力破解。只要服务器开了 22 端口,每天扫过来的密码尝试就有成百上千次,不信可以翻一翻日志。很多个人站长觉得"我的站没什么价值,黑客看不上",实际上攻击者根本不挑目标,全是自动化脚本在扫,密码简单的机器分分钟就被拿下。这篇文章分享一套完整的 SSH 安全加固方案:从密钥登录、sshd 配置收紧,到 fail2ban 自动封禁,一步到位把大门守好。

一、先看看你的服务器正在被怎么攻击

动手加固之前,先花两分钟看看现状,你会对威胁有直观的认识。查看登录失败记录:

# 查看所有用户的最近登录记录
lastlog

# 查看登录失败次数(部分发行版在 /var/log/btmp)
sudo lastb | head -30

# Debian/Ubuntu 查看认证日志里的失败尝试
sudo grep "Failed password" /var/log/auth.log | wc -l

# CentOS/RHEL 用 secure 日志
sudo grep "Failed password" /var/log/secure | wc -l

统计一下失败次数,再按来源 IP 排个序:

sudo grep "Failed password" /var/log/auth.log | grep -oP "from \K[0-9.]+" | sort | uniq -c | sort -rn | head -20

你会看到攻击 IP 来自全球各地,有些 IP 一天之内尝试几百次。这就是自动化扫描爆破的典型特征。明白了威胁真实存在,才有动力把加固做扎实。

二、第一步:改用密钥登录

密码登录最大的问题是可被暴力尝试,而密钥登录基于非对称加密,没有私钥的人无论如何都登不进来,爆破在密钥面前完全失效。这是整个加固方案里最核心的一步。

首先在本地电脑上生成密钥对。现代系统强烈推荐 ed25519 算法,它比 RSA 更安全、更快、密钥更短:

# 在本地电脑执行,不是在服务器上
ssh-keygen -t ed25519 -C "your_email@example.com"

一路回车即可,也可以给私钥设置一个口令(passphrase),这样即使私钥文件泄露,别人也无法直接使用。生成后会在 ~/.ssh/ 下产生两个文件:id_ed25519 是私钥,绝不能外传;id_ed25519.pub 是公钥,可以放心分发。

然后把公钥安装到服务器上:

ssh-copy-id -i ~/.ssh/id_ed25519.pub user@服务器IP

ssh-copy-id 会自动把公钥追加到服务器上对应用户的 ~/.ssh/authorized_keys 文件里,并设置好权限。如果没有 ssh-copy-id 命令,也可以手动操作:把公钥内容复制下来,登录服务器后执行:

mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "粘贴公钥内容" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

注意权限非常重要:~/.ssh 目录必须是 700,authorized_keys 必须是 600。权限过松的话,sshd 出于安全考虑会直接忽略这个文件,导致密钥登录不生效,这是新手最常踩的坑。

装好公钥后,先不要关掉密码登录,另开一个终端用密钥登录测试一次,确认能正常登入,再进入下一步。

三、第二步:收紧 sshd 配置

密钥登录验证通过后,编辑 sshd 配置文件 /etc/ssh/sshd_config,逐项收紧。每一项改完都建议先用 sshd -t 检查语法,确认无误再重启服务。

第一项,禁止 root 直接登录。root 是攻击者最想拿下的账号,禁用 root 直接 SSH 登录,改用普通用户登录后 su 或 sudo 提权:

PermitRootLogin no

这样即使攻击者猜中了 root 密码也无法直接登录。如果你用的是云服务器厂商提供的 root 账号,建议先创建一个普通用户并加入 sudo 组,测试普通用户能登录后再启用这一项。

第二项,禁用密码登录,只允许密钥:

PasswordAuthentication no
PubkeyAuthentication yes

这两行一开,密码爆破就彻底失效了。但务必确认密钥登录已经稳定可用再改,否则容易把自己锁在门外。

第三项,限制登录尝试次数和超时时间:

MaxAuthTries 3
LoginGraceTime 30

MaxAuthTries 限制单次连接最多尝试 3 次认证,超过即断开;LoginGraceTime 30 表示 30 秒内没完成认证就断开连接,防止攻击者挂着一堆半开连接占用资源。

第四项,限制可登录的用户。只允许指定的用户通过 SSH 登录:

AllowUsers zhangsan lisi

白名单之外的用户一律无法登录,包括系统里的其他账号。这条对服务器上开了多个账号的场景特别有用。

第五项,关闭无关的转发功能,减少被利用的面:

X11Forwarding no
AllowTcpForwarding no

如果不是确实需要端口转发和 X11 图形转发,关掉更安全。另外建议开启:

UseDNS no

UseDNS no 可以避免 sshd 对客户端做反向 DNS 解析,既加快登录速度,也避免 DNS 服务异常导致登录卡顿甚至被拒绝。

关于修改 SSH 端口:把 22 改成其他高位端口(比如 2222)确实能减少大量扫描流量,但注意这是"降低被扫概率"而不是"提升安全性",真正的安全靠的是密钥和 fail2ban。改端口前记得同步修改防火墙规则,并测试新端口能连上。我个人建议:如果服务器上跑的站点多、日志要经常排查,保留 22 端口配合 fail2ban 也完全够用;如果很在意被扫描的噪音,改端口也是个合理选择。

全部改完后:

# 检查语法
sudo sshd -t
# 重启服务
sudo systemctl restart sshd

重启之后立刻新开一个终端测试登录,确认没有把自己锁在外面,再关闭当前会话。

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

密钥登录加上之后,密码爆破已经无效,但攻击者还会继续尝试,日志里会持续出现大量失败记录,占用系统资源。fail2ban 的作用就是监控日志,发现某个 IP 短时间内失败次数过多,就自动把它拉黑一段时间,从源头掐断攻击。

安装 fail2ban(Debian/Ubuntu):

sudo apt update
sudo apt install -y fail2ban

CentOS/RHEL 用:

sudo yum install -y epel-release
sudo yum install -y fail2ban

fail2ban 的默认配置在 /etc/fail2ban/jail.conf,不要直接改它,升级软件时会被覆盖。正确的做法是新建一个 /etc/fail2ban/jail.local,里面的配置会覆盖默认值。写一个最实用的 SSH 防护配置:

[DEFAULT]
# 允许的 IP 白名单,写你自己的固定 IP
ignoreip = 127.0.0.1/8 你的固定IP

# 默认封禁时长:1 小时
bantime = 3600
# 查找窗口:10 分钟内
findtime = 600
# 触发封禁的失败次数
maxretry = 3

[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s

这段配置的含义:同一个 IP 在 10 分钟内认证失败 3 次,就封禁 1 小时。封禁时间可以根据需要调整,个人服务器建议 bantime 直接设大一点,比如 86400(一天)甚至更长,反正正常用户不会在一天内输错几次密码。

如果修改了 SSH 端口,把 [sshd] 里的 port 改成实际端口号,比如:

[sshd]
enabled = true
port = 2222

启动并检查状态:

sudo systemctl enable fail2ban
sudo systemctl start fail2ban
# 查看封禁状态
sudo fail2ban-client status sshd

还可以查看当前被封的 IP 列表:

sudo fail2ban-client status sshd | grep "Banned IP list" -A 5

如果确认某次封禁是误伤(比如自己输错密码被拉黑),手动解封:

sudo fail2ban-client set sshd unbanip 你的IP

这里提醒一个细节:如果你的服务器在防火墙层面(比如云厂商安全组、ufw、firewalld)没有放行某些端口,fail2ban 默认通过 iptables 添加封禁规则。配置完成后建议观察一两天,确认规则确实在生效,并且没有把正常用户误封。

五、第四步:兜底与监控

除了上面三步,还有几件小事建议一起做。

第一,给登录失败加通知。可以在 fail2ban 的 action 里配置邮件或 Webhook 通知,每次封禁 IP 时通知自己。个人站长如果不想折腾邮件,也可以用脚本把封禁记录追加到一个文件,配合定时任务定期查看。

第二,定期检查 authorized_keys。确认里面的公钥都是你自己放的,发现陌生公钥立即删除,那可能意味着服务器已经被入侵过。检查方法:

cat ~/.ssh/authorized_keys

第三,做好密钥备份。私钥丢失意味着你再也登不上服务器(密码登录已禁用的情况下),把私钥备份到安全的地方,比如加密的 U 盘或密码管理器。私钥本身要设置口令,双重保险。

第四,关注系统更新。SSH 相关的安全漏洞虽然少见,但一旦出现影响很大。养成定期更新系统的习惯:

sudo apt update && sudo apt upgrade -y

第五,如果服务器还开着其他服务,比如网站面板、数据库远程端口,同样要确认它们的口令强度和访问控制。SSH 只是大门,门里的每个房间也要锁好。

六、别把自己锁在门外:操作安全清单

加固操作最大的风险不是被攻击,而是把自己锁在门外。遵守下面几条,基本不会翻车:

第一,永远先测试再禁用。启用密钥登录后,先开新终端验证密钥能登录,再关密码登录。改端口同理,先确认新端口能连,再决定是否关闭旧端口。

第二,保留一个逃生通道。云服务商的控制台一般都有 VNC 或网页终端(比如阿里云的 Workbench、腾讯云的 VNC),万一 SSH 配置改坏了,还能从控制台进去修复。动手前先确认这个通道可用。

第三,改动要小步走。一次只改一两项,测通了再改下一项。一次性改完一大堆配置,出了问题都不知道是哪条引起的。

第四,sshd 配置改完用 sshd -t 检查语法,语法错误会导致 sshd 拒绝启动,等于直接断了自己的路。这个命令虽然简单,但能救命的。

七、常见问题 FAQ

问:我改了 sshd_config 重启后连不上了怎么办? 不要慌,先确认网络通不通,再通过云控制台的网页终端登录服务器,把配置改回去并重启 sshd。如果网页终端也进不去,部分云厂商支持"救援模式"或"重置密码",这是最后的办法。所以改配置前务必确认控制台通道可用。

问:fail2ban 会不会误封正常用户? 有可能。如果办公室出口 IP 是共享的,别人输错密码可能连累你。解决办法是把固定 IP 写进 ignoreip 白名单,或者适当提高 maxretry。个人服务器通常不用太担心,误封了手动 unban 即可。

问:密钥文件丢了还能登录吗? 如果密码登录已被禁用,私钥丢了基本等于进不去。所以务必在禁用密码登录之前就做好密钥备份。真的丢了,只能靠云控制台或救援模式重置,重置后重新配置密钥。

问:我的是宝塔面板管理的服务器,这些配置还适用吗? 适用。宝塔面板只是帮你管理 Nginx、PHP 这些应用,SSH 加固照做不误。宝塔自带的 SSH 管理功能里也能配置密钥和 fail2ban,但理解原理后手动配置更可控。

问:ed25519 和 RSA 有什么区别,老服务器支持吗? ed25519 是较新的算法,性能好、密钥短、安全性高,现代 Linux 发行版(CentOS 7 之后的版本基本都支持)都能用。如果遇到非常老的服务器不支持,可以用 RSA 4096 位作为替代,同样安全。

SSH 加固是投入产出比最高的一项服务器安全操作,半天时间就能完成,换来的是服务器大门长期安稳。别等到哪天真被爆破进来、网站被挂马了才后悔,现在就动手把密钥登录和 fail2ban 配起来吧。

Last modification:August 8th, 2026 at 08:20 am

Leave a Comment