打开日志一看,几千条 Failed password for root from ...,这是很多运维第一次直观感受到"自己被盯上了"。暴力破解的本质不是有人专门盯你,而是全网扫描器在对所有开放 22 端口的机器做批量尝试,谁用弱口令谁中招。真正危险的不是日志有多吵,而是其中某一次碰巧成功了。
这篇文章讲三件事:怎么从日志里判断自己正在被爆破以及来源分布,怎么用 fail2ban 建立自动封禁,以及怎么用 sshd 配置、来源 IP 限制和端口敲门把暴露面进一步收窄。全文都是防御视角,不涉及任何攻击工具的使用。过程中会反复强调一件事:任何封禁操作都要先把自己的出口 IP 加进白名单,并预留带外通道,否则下一个被挡在门外的就是你自己。
先确认:这是不是暴力破解
第一步是看日志,而不是急着改配置。日志能告诉你来源有多少、频率多高、针对哪些用户名,这些信息决定了后面的处置力度。
RHEL、Rocky、CentOS 的 SSH 认证日志在 /var/log/secure,Debian、Ubuntu 在 /var/log/auth.log。使用 systemd 的系统也可以用 journalctl 直接查:
# RHEL、Rocky、CentOS
sudo grep 'Failed password' /var/log/secure | tail -50
# Debian、Ubuntu
sudo grep 'Failed password' /var/log/auth.log | tail -50
# 通用(systemd)
sudo journalctl -u sshd -u ssh --since '24 hours ago' | grep 'Failed password'
看到输出后,先做统计,找出最主要的来源:
# 统计失败次数最多的来源 IP(取前 20)
sudo grep 'Failed password' /var/log/auth.log \
| grep -oP 'from \K[0-9.]+' | sort | uniq -c | sort -rn | head -20
# 统计被尝试最多的用户名
sudo grep 'Failed password' /var/log/auth.log \
| grep -oP 'for (invalid user )?\K[a-zA-Z0-9_-]+' | sort | uniq -c | sort -rn | head -20
# 统计失败总次数
sudo grep -c 'Failed password' /var/log/auth.log
如果同一个 IP 在几分钟内出现几十上百次失败,基本可以确定是自动化的字典爆破。如果来源 IP 分布很散、每个只试几次,那属于分布式慢速爆破,这种更难防,靠 fail2ban 的单 IP 阈值效果有限,需要靠禁用密码登录来根治。
另外两个常用命令:
sudo lastb | head -30 # 查看失败登录记录(读取 /var/log/btmp)
sudo lastb -i | awk '{print $3}' | sort | uniq -c | sort -rn | head
sudo last | head -20 # 查看成功登录记录
sudo lastlog | grep -v 'Never' # 查看各账号最近登录时间
lastb 依赖 /var/log/btmp,有些系统默认不生成该文件,执行一次 lastb 或手动创建后才会记录。如果 last 里出现了你不认识的登录时间、来源 IP 或账号,说明可能已经成功过,这时的处置流程要按应急事件处理,而不是单纯加固。
判断依据可以总结成这样一张表:
| 观察项 | 正常情况 | 异常信号 |
|---|---|---|
| 每小时失败次数 | 个位数或零 | 上百甚至上千 |
| 来源 IP 分布 | 集中且熟悉 | 大量陌生境外 IP |
| 尝试的用户名 | 自己的账号 | root、admin、test、oracle 等字典词 |
| 成功登录记录 | 与自己的操作吻合 | 出现陌生 IP 或陌生时间 |
| 失败时间分布 | 零散 | 集中在夜间、间隔规律 |
一旦出现"成功登录记录里有陌生来源"这一条,立刻转入应急响应:改所有口令、轮换密钥、排查新增账号与计划任务,必要时按被入侵处理。
用 fail2ban 建立自动封禁
fail2ban 的思路很直接:持续扫描日志,匹配到失败模式后累计计数,超过阈值就把来源 IP 加入防火墙封禁一段时间。它不能替代密钥登录,但能显著降低噪音和爆破成功率。
# RHEL、Rocky、CentOS(需 EPEL)
sudo dnf install -y epel-release
sudo dnf install -y fail2ban fail2ban-firewalld
# Debian、Ubuntu
sudo apt update && sudo apt install -y fail2ban
sudo systemctl enable --now fail2ban
配置文件不要直接改 jail.conf,升级时会被覆盖。正确做法是写 jail.local:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo vi /etc/fail2ban/jail.local
关键参数如下:
[DEFAULT]
# 白名单:务必把自己的出口 IP、办公网、监控节点写进去
ignoreip = 127.0.0.1/8 ::1 你的办公网出口IP 内网网段
# 封禁时长,单位秒。600 = 10 分钟,86400 = 一天
bantime = 3600
# 统计窗口,这段时间内累计失败
findtime = 600
# 允许的失败次数
maxretry = 5
# 递增封禁:反复被封的 IP 时间越来越长
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 604800
# 后端,systemd 系统推荐用 systemd
backend = systemd
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log # RHEL 系改为 /var/log/secure
maxretry = 3
findtime = 600
bantime = 86400
几个参数的含义要理解清楚,不然调优无从下手:
maxretry:窗口内允许的失败次数,超过就封。SSH 建议设 3,正常输错密码不会超过这个数。findtime:统计窗口长度,单位秒。设 600 表示"10 分钟内失败 3 次就封"。bantime:封禁时长。设太短对方会换个 IP 继续,设太长可能误伤动态 IP 的合法用户。一天是比较平衡的值。ignoreip:最重要的一项,漏写自己的 IP 是最常见的翻车原因。云服务器的公网出口 IP、公司固定 IP、监控探针、跳板机都要列进去,支持 CIDR 网段写法。
backend = systemd 在较新的发行版上比轮询日志文件更可靠,也避免了日志轮转导致的漏读。如果发行版较老或 journal 未持久化,用默认的 auto 或 polling 也可以。
配置完成后:
sudo fail2ban-client -t # 语法检查
sudo systemctl restart fail2ban
sudo fail2ban-client status # 查看启用的 jail
sudo fail2ban-client status sshd # 查看 sshd jail 的封禁列表
sudo fail2ban-client set sshd unbanip 1.2.3.4 # 手动解封
风险提示:fail2ban 默认通过 iptables 或 firewalld 添加封禁规则。如果你同时在用 nftables 或云安全组,要确认 banaction 与之匹配,否则会出现"日志显示已封禁但流量照样进来"的情况。RHEL 系建议安装 fail2ban-firewalld 并把 banaction 设为 firewallcmd-rich 或 firewallcmd-ipset。
被自己误封的抢救办法:如果还能连上,执行上面的 unbanip;如果已经连不上,先用云控制台的 VNC 或串口终端登录,执行 sudo fail2ban-client unban --all 清空所有封禁,再把正确的 IP 写进 ignoreip。所以带外通道永远要先确认可用。
sshd 配置加固:减少爆破的价值
fail2ban 是在被爆破之后响应,sshd 配置则是让爆破本身变得没有意义。下面这组配置建议逐步启用,每改一项验证一次:
sudo cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F)
sudo vi /etc/ssh/sshd_config
# 禁止 root 直接登录(需先有可用的 sudo 普通用户)
PermitRootLogin no
# 只允许密钥,彻底杜绝口令爆破(需先验证密钥可用)
PasswordAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
# 禁止空口令
PermitEmptyPasswords no
# 单次连接的认证尝试次数
MaxAuthTries 3
# 登录宽限时间,超时断开,防慢速占用
LoginGraceTime 30
# 白名单用户,名单外一律拒绝
AllowUsers ops deploy
# 限制并发未认证连接数,抑制并行爆破
MaxStartups 10:30:60
每一项的含义和注意点:
PermitRootLogin no 执行前,必须已经能用普通用户登录并且 sudo 提权正常,否则 root 一禁就没人能登录了。
PasswordAuthentication no 是防爆破最彻底的一招,因为没有口令可猜。前提是密钥已经配好并验证通过。配置密钥时注意 ~/.ssh 目录 700、authorized_keys 文件 600,权限不对会导致密钥登录静默失败。
AllowUsers 一旦启用就是白名单机制,名单外的用户即使凭证正确也会被拒。所以要把所有需要登录的账号都列进去,用空格分隔。也可以用 AllowGroups 配合用户组管理,规模大了更好维护。
MaxStartups 10:30:60 的含义是:未认证连接数达到 10 后,开始按 30% 的概率丢弃新连接,达到 60 后全部丢弃。这能抑制并行爆破把 sshd 的连接资源耗尽。
改完照例校验并重启:
sudo sshd -t && echo "语法正常"
sudo systemctl restart sshd # Debian、Ubuntu 用 ssh
sudo ss -lntp | grep sshd
务必保留当前会话不关闭,另开新窗口验证登录成功后,才算完成。
按来源 IP 限制:效果最强的一招
如果运维人员的出口 IP 相对固定(办公网固定 IP、跳板机、VPN 出口),把 22 端口只对这几个来源放行,是最彻底的做法:攻击者的包根本到不了 sshd,日志里也不会有任何记录。
# RHEL、Rocky、CentOS:firewalld rich rule
sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --permanent \
--add-rich-rule='rule family="ipv4" source address="203.0.113.10/32" port protocol="tcp" port="2222" accept'
sudo firewall-cmd --reload
sudo firewall-cmd --list-rich-rules
# Debian、Ubuntu:ufw
sudo ufw allow from 203.0.113.10 to any port 2222 proto tcp
sudo ufw deny 2222/tcp
sudo ufw reload
sudo ufw status numbered
ufw 的规则按顺序匹配,先放行后拒绝,顺序错了会全部拒绝。用 ufw status numbered 查看序号,用 ufw delete 序号 删除错误规则。
nftables 的做法是用集合管理,便于批量维护:
sudo nft add table inet filter
sudo nft add set inet filter ssh_allow '{ type ipv4_addr; flags interval; }'
sudo nft add element inet filter ssh_allow '{ 203.0.113.10, 198.51.100.0/24 }'
sudo nft add chain inet filter input '{ type filter hook input priority 0; policy drop; }'
sudo nft add rule inet filter input tcp dport 2222 ip saddr @ssh_allow accept
sudo nft list ruleset
云上还应该在安全组层面做同样限制,安全组是云平台侧的访问控制,在系统防火墙之前生效,双层收敛更稳妥。风险提示:配置来源限制前先确认自己的公网出口 IP,可以用 curl ifconfig.me 之类的服务查看;如果是动态 IP 的家庭宽带,不要用这种方式,或者同时保留一个备用放行网段和带外通道。
端口敲门 knockd 的思路
端口敲门是一种"隐式白名单":sshd 端口默认对所有来源关闭,只有按约定顺序访问过几个指定端口之后,防火墙才临时为这个 IP 打开 SSH 端口。它适合出口 IP 不固定的移动运维场景,作为固定 IP 白名单的补充手段。
基本思路是守护进程监听防火墙日志,识别到符合顺序的"敲门"序列后,临时添加放行规则,若干秒后自动撤销。常见实现是 knockd,配置里定义序列、超时窗口和开门时长。
它的局限也要清楚:敲门序列在网络上以数据包形式出现,同一网段内的观察者有可能记录下来并重放;它依赖额外的守护进程,进程挂了就进不去;排障时容易把自己绕晕。因此它只能作为辅助手段,不能替代密钥登录,而且必须同时保留带外通道。对绝大多数中小企业来说,固定 IP 白名单加堡垒机的组合比端口敲门更实用、更好维护。
被持续爆破时的处置与告警
当日志显示爆破持续且量级很大时,按下面的顺序处置:
第一,确认没有成功记录。 用 last、lastlog、grep 'Accepted password\|Accepted publickey' 检查成功登录,这是判断事件严重性的分水岭。有陌生成功记录就按入侵应急处理。
第二,立刻改用密钥并禁用密码登录。 这一步能从根本上终止爆破的价值,比任何封禁都有效。
第三,收敛来源。 能在安全组和防火墙限制来源 IP 的,全部限制;不能限制的,靠 fail2ban 把阈值调紧,并启用递增封禁。
第四,把日志接入告警。 单机上封几千个 IP 意义有限,因为对方 IP 池很大。真正有用的是让异常被看见:
# 简单的每日统计脚本思路,配合 cron 和邮件或 webhook 发出
#!/bin/bash
COUNT=$(grep 'Failed password' /var/log/auth.log | grep -c "$(date +%b\ %e)")
BANNED=$(fail2ban-client status sshd | grep -oP 'Currently banned:\s+\K[0-9]+')
echo "$(date +%F) 失败 $COUNT 次,当前封禁 $BANNED 个" | \
mail -s "SSH 登录日报 $(hostname)" ops@example.com
告警的关键是设定基线和阈值:当失败次数比上周同一时段高出数倍,或者短时间内突增,就应该触发人工介入。建议同时监控"当前封禁 IP 数"这个指标,它比绝对失败数更能反映攻击强度。
第五,考虑前置堡垒机或零信任接入。 当机器数量增多,逐台配置白名单会失控。统一入口做认证、审计和授权,后端机器只对堡垒机开放 SSH,是规模化之后的必然选择。
常见问题
把 IP 封了,对方换个 IP 继续怎么办?
这是分布式爆破的常态,单机封禁确实治标。根本解法是禁用密码登录:没有口令可猜,换多少 IP 都没用。其次是收敛来源和接入堡垒机,让 SSH 根本不对公网可见。
fail2ban 封禁了我自己的 IP,现在连不上了?
用云控制台的 VNC 或串口终端登录,执行 sudo fail2ban-client unban --all 解封全部,再把自己的 IP 和网段写进 jail.local 的 ignoreip 后重启服务。所以配置 ignoreip 时宁可多写一段内网和备用出口,也别漏。
日志里出现大量不认识的用户名,是被盯上了吗?
root、admin、test、oracle、postgres 这类字典用户名出现在失败记录里是常态,说明扫描器在试通用账号,不代表你有这些账号。只要确认 /etc/passwd 里没有这些账号、且密码登录已禁用,风险就很低。
改了 sshd 配置后服务起不来怎么办?
先用 sshd -t 看报错行号,通常是参数名拼错或值不合法。如果已经重启失败导致服务停了,只要当前会话还没断,就地改回备份文件重启即可;会话已断就走 VNC。所以每次改配置前都要 cp -a 备份。
bantime 设多久合适?
个人和小团队建议 3600 起步,配合递增封禁;有固定 IP 白名单的场景可以设到 86400 甚至更长。设太短(比如 60 秒)几乎没效果,因为爆破脚本会自动重试。
总结
- 判断被爆破先看日志:
grep 'Failed password'统计来源 IP 与用户名,lastb、last、lastlog确认有没有陌生成功记录;有成功记录就按入侵应急处理。 fail2ban的核心是ignoreip、maxretry、findtime、bantime四个参数,ignoreip漏写自己是最常见的翻车原因,配置后要确认banaction与系统防火墙后端匹配。- sshd 加固按
PermitRootLogin no、PasswordAuthentication no、AllowUsers、MaxAuthTries、LoginGraceTime逐项启用,每改一项在新窗口验证一次,旧会话全程不关。 - 出口 IP 固定时,用 firewalld rich rule、ufw 或 nftables 集合做来源限制,配合云安全组双层收敛,效果强于任何事后封禁;端口敲门只作为补充手段且必须留带外通道。
- 持续的分布式爆破靠封 IP 治不了本,根治手段是禁用密码登录、收敛来源、接入堡垒机,并把失败次数与封禁数做成带阈值的告警。
企业QQ咨询




