☰
SSH暴力破解应急响应与安全加固实战指南
2026/10/19 9:15:26 网站建设 项目流程

凌晨两点多,手机连着响了七八声,全是监控报警。登录服务器看了一眼,整个/var/log/secure文件刷得飞快,全是Failed password for root,一秒好几条,来自同一个 IP,连着试了十几个用户名。不用猜,这是典型的暴力破解,密码字典正在扫我的 SSH 端口。

那天晚上我处理完已经是凌晨五点,事后写了一份排查记录,顺手把这段时间反复踩过的坑、验证过的方案都整理出来。这篇文章不写空话,全是实际操作,从发现入侵、止血止损,到日志取证、加固防护,最后到长期监控,一步步给你拆开讲。如果你也遇到类似情况,按这个流程走一遍,至少不会再手忙脚乱。

1. 事件定性:先搞清攻击到了哪一步

1.1 暴力破解攻击的本质

暴力破解这个东西,原理一点都不神秘。攻击者手里有一份很大的字典文件,里面装满了常见的用户名和密码组合,比如admin/123456、root/password、test/test之类的,然后用脚本一遍一遍往你服务器的 SSH 端口发登录请求。密码对了就能登进去,不对就换下一个。单个请求只有几百字节,攻击机带宽稍微好一点,一秒钟就能打几十上百次尝试。

这类攻击有三个明显特征,你在日志里一眼就能认出来:

  • 同一个 IP 在短时间内发起大量登录失败请求,频率远超正常人手动操作;
  • 用户名字典组合是「扫射式」的,root、admin、test、oracle、ubuntu轮着来,有时候还会带大小写变种;
  • 攻击时间往往集中在下半夜或者业务低谷期,因为爆破会产生大量日志,白天的运维容易第一时间发现。

我这次遇到的就是典型的第一种,一个 IP 在十分钟内发了快八百次登录请求,用的用户名列表覆盖了几十个常见账号。好在服务器上的root密码是 28 位随机生成的,密码策略也强制启用了,所以密码本身没被怼开,但光是这种日志刷屏和连接风暴,就够让人头疼的。

1.2 入侵影响面评估:别急着下结论

很多人看到暴力破解日志第一反应是「完了,被入侵了」,然后慌慌张张去断网、重装系统,结果证据没保存,业务也停了。正确的做法是先冷静评估攻击是否成功,分三档处理:

  • 阶段一(仅尝试,无成功):日志里全部是Failed password,没有看到Accepted password,说明攻击者还在撞库阶段,内部系统没有被突破。处理方式以阻断和加固为主。
  • 阶段二(存在成功登录记录):日志里出现了Accepted password for 某用户 from 某IP,说明至少有一个账号被攻破了。这时候要立刻隔离服务器,防止横向扩散。
  • 阶段三(已经执行了命令且可能有后门):不仅是登录成功,/root/.bash_history或审计日志里还出现了可疑命令,比如下载脚本、添加用户、修改定时任务等。这时候已经不适合线上排查了,建议镜像保留现场后,重装系统或从干净备份恢复。

我当时对照日志查了一圈,确认是阶段一,才敢继续原地排查。这个判断非常关键,因为它决定了后续所有操作的风险等级。

提示:暴力破解和价值直接相关的服务器(数据库、钱包节点、权限管理后台)不止是登录尝试,还要检查是否有登录成功后提权行为。判断入侵程度一定基于日志证据,不要靠猜测。日志取证在任何步骤之前。

2. 应急止损:攻击还在继续,第一时间做什么

2.1 立即阻断攻击源头

先说最紧急的:把当前正在攻击的 IP 断掉。这一步不需要精细操作,谁打你你关谁,动作要快。最直接的手段是操作系统的防火墙,比如用iptables、firewalld或ufw临时拉黑该 IP:

# 使用 iptables 临时封禁攻击 IP(仅阻断,不删除规则) iptables -I INPUT -s 5.188.206.32 -j DROP # 如果用的是 firewalld firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="5.188.206.32" drop' firewall-cmd --reload # 使用 ufw 封禁 ufw insert 1 deny from 5.188.206.32

我在实际处理中用的就是iptables -I INPUT的方式,-I表示把规则插到最前面,旧的规则不冲突就能立刻生效。如果攻击源 IP 一直在变,比如扫了整个段,可以先临时封掉最活跃的几个,再接着做下面的加固。

需要解释一下为什么不直接改 sshd 配置来止血——因为改配置要重启服务,重启期间新连接会断,如果攻击流量还在打,可能出现连接雪崩。防火墙封 IP 是即时生效的,对存量连接不影响,对攻击流量直接丢弃,处理优先级应该最高。

2.2 切换 SSH 端口并限制登录

把攻击流量暂时挡住之后,下一个动作就是把 SSH 默认的 22 端口换掉。暴力破解脚本百分之九十九是默认扫 22 端口,改了端口相当于把大门从主干道搬到小巷子里,哪怕密码简单,也会把绝大多数扫描挡在门外。

编辑/etc/ssh/sshd_config:

# 修改前先确认新端口没有被占用 # ss -lntp | grep 2022 Port 2022

然后重载服务:

sshd -t && systemctl reload sshd

这里有两个非常关键的细节,踩过坑的都懂:

  • 改端口前一定要先把自己当前的 SSH 连接保住。我是开着两个终端窗口操作的,一个改了配置先不重载,另一个用ssh -p 2022做连接测试,测试通过了再重载。否则一旦配置写错,重载后原连接断掉,你只能去物理机或者云厂商的 VNC 控制台救急。
  • 改端口要记得同步改云安全组。我用的云服务器的安全组策略默认只放行了 22 端口,如果开了防火墙却没改云平台策略,新的 2022 端口照样连不上,而且这个问题容易和系统防火墙混淆,排查半天才发现是安全组没加。

同时把/etc/ssh/sshd_config里的PermitRootLogin改成no,关闭 root 直接登录。原因很简单:root 是操作系统的超级账号,暴力破解字典里 99% 会包含root这个用户名。关掉 root 直登并不会让你没法管理服务器,日常运维完全可以先登录普通用户,再通过sudo切换到 root。这样一来,攻击者扫到 root 也无门可入,只能去猜普通用户名,成本翻了好几倍。

我还顺手把LoginGraceTime改成了 30 秒,超过 30 秒不认证就断开。这样做的好处是防止有人挂起大量半连接来占满 sshd 的进程,算是一种轻量的防扫描手段。

2.3 检查是否存在异常账号和后门

止血不止是封 IP、改端口。攻击如果已经深入到了系统内部,你光堵住入口没有用,对方可能已经留了后门。所以在端口和密码问题处理完之后,必须要对账号和计划任务做一次快速体检。

检查账号:

# 列出了所有用户,确认没有异常新增账号 awk -F: '$3==0{print $1}' /etc/passwd # 检查是否有空密码账号,这类账号等于裸奔 awk -F: '($2==""){print $1}' /etc/shadow

检查计划任务:

# 系统级计划任务 ls -la /etc/cron.d/ /etc/cron.daily/ /var/spool/cron/ # 当前用户计划任务(root 和其他用户都看一下) crontab -l

检查自启动项:

# 查看已经加载的服务,注意和正常业务对比 systemctl list-unit-files --type=service --state=enabled

这轮检查的目的是确认攻击者有没有在系统里「扎根」。如果发现不明账号、可疑的 cron 任务、新增的服务,说明攻击已经不止是爆破登录这么简单了。对于阶段一、阶段二的攻击,这些检查结果应该是干净的。我在处理时确认了/etc/passwd里没有uid=0的新账号,crontab -l输出为空,/root/.bash_history只有自己的操作记录,才放下心来进入下一步排查。

3. 日志取证:还原攻击者的完整操作路径

3.1 关键日志文件和取证命令

攻击源封了,后门查了,下一步要做的是把日志完整保存下来,作为事件分析和后续安全审计的依据。取证这件事很多人觉得无所谓,真出问题的时候才后悔没存日志。

Linux 系统里和 SSH 登录相关的日志文件主要看发行版:

  • CentOS / RHEL:主要看/var/log/secure,里面记录了完整的安全认证事件;
  • Ubuntu / Debian:主要看/var/log/auth.log,作用和secure一样;
  • /var/log/messages或journalctl:可以看系统整体状态,但一般不需要全量翻。

我先做的是把日志文件直接复制一份出来,备份到一个安全目录:

mkdir -p /opt/security_evidence/$(date +%Y%m%d%H%M%S) cp /var/log/secure /var/log/auth.log /opt/security_evidence/$(date +%Y%m%d%H%M%S)/ 2>/dev/null

然后开始分析。第一步是看成功登录的记录,这个优先级最高。命令:

# 在 CentOS 上查成功登录记录 grep "Accepted password" /var/log/secure | awk '{print $1,$2,$3,$9,$11}' # 在 Ubuntu 上 grep "Accepted password" /var/log/auth.log | awk '{print $1,$2,$3,$9,$11}'

输出这样的记录:

Feb 18 03:12:22 root 5.188.206.32 Feb 18 03:13:45 root 5.188.206.32

看到这两条的时候我愣了一下,因为刚才已经确认过没有 Accept 记录,这可能是攻击者尝试成功后又退出了。继续往下查发现是同 IP 的多次尝试,中间有一次密码确实匹配了——这就属于阶段二了。排查时要特别留意这种「一次成功 + 多次失败」的混合模式,攻击者可能用正确密码进来过一次,然后再用别的字典继续试,就是为了确认账号有效性。

3.2 用命令快速统计攻击特征

日志文件动辄几万行,人肉翻不现实。我做了个简单的统计,把攻击源的 IP、尝试次数和被尝试的用户名列出来,很快就看清了整体攻击模式。

统计攻击 IP 和次数:

grep "Failed password" /var/log/secure | awk '{print $(NF-3)}' | sort | uniq -c | sort -nr | head -20

我拿到的最前面的输出大概是:

812 5.188.206.32 126 10.2.4.77 43 103.74.192.15

统计被尝试的用户名:

grep "Failed password" /var/log/secure | awk '{print $(NF-5)}' | sort | uniq -c | sort -nr | head -20

输出会清晰显示攻击者字典里的用户名分布,比如:

512 root 138 admin 96 test 45 oracle 23 tomcat

这些统计数字有两个用途:一是给攻击定性写报告用;二是如果你需要去云平台投诉或找网警报案,有明确的证据链。我看到 top 用户的分布后,也顺带把系统里所有账号密码重新过了一遍——尤其检查了root、admin、test这些账号是不是还在用弱密码。接着我上调了所有账号的密码复杂度要求,防止攻击者字典里真就撞上一个。

3.3 顺藤摸瓜排查可疑行为轨迹

暴力破解不一定是攻击的最终目的。有些攻击者成功登录后会立刻执行某些命令,比如下载挖矿程序、替换系统命令、创建隐藏账号。我建议从成功登录的时间点往后推,把/var/log/messages里相关时间段的异常行为也拉出来看看。

具体做法是把成功登录时间点前后五分钟的日志单独切出来:

# 先记录成功登录的时间点 grep "Accepted password" /var/log/secure # 然后以这个时间为锚点查前后日志 grep "Feb 18 03:1[2-5]" /var/log/secure | grep -v "Failed password"

还要检查 shell 历史记录。正常人是不会在服务器上手动敲wget+ 脚本下载地址的,但自动化攻击工具会。用这个命令排查:

cat /root/.bash_history | grep -E "wget|curl|nc |/dev/tcp|chmod \+x|useradd|passwd"

如果发现有下载脚本、添加账号、开放端口的操作记录,那就要按阶段三来升级处理了。这里必须强调:先获取和保存证据,再考虑处置动作。很多新手一看到可疑命令,立刻删文件、杀进程、改密码,结果操作完了发现没法追溯攻击者到底干了什么。合理的顺序是备份日志、记录时间点、截图取证,再做处置。

4. 系统加固:把暴力破解的门彻底堵死

4.1 密码策略和账号安全配置

暴力破解攻击成功的唯一前提是密码被猜中。那么把密码做得极其难猜,就算日志里刷满失败记录,攻击者也进不来。这一步是我在事件后花时间最多的地方。

修改 Linux 密码策略需要用到pam模块。我直接改/etc/security/pwquality.conf和/etc/login.defs,把密码最小长度设为 16 位、同时启用复杂度和新旧密码不能相同的限制:

# /etc/security/pwquality.conf minlen = 16 dcredit = -1 ucredit = -1 lcredit = -1 ocredit = -1

每行的含义拆开讲一下:

  • minlen=16:密码最短 16 位;
  • dcredit=-1:至少包含 1 个数字;
  • ucredit=-1:至少包含 1 个大写字母;
  • lcredit=-1:至少包含 1 个小写字母;
  • ocredit=-1:至少包含 1 个特殊字符。

/etc/login.defs里还有一个叫PASS_MAX_DAYS的参数,我改成了 90,意思是密码每 90 天必须换一次。配合PASS_MIN_DAYS设为 7,防止用户改回原密码。这样就算某个密码意外泄露,有效期最多 90 天,到期后攻击者手里那张「旧门票」自动作废。

同时把所有用户密码重新生成了一遍。生成密码的规则是保长度、弃规律,我是通过系统内置的随机数发生器生成的,而不是人工去编一段「好记」的密码。人工编密码的规律性太强,字典攻击很容易命中模式;随机密码没有模式可言,暴力破解的复杂度指数级上升。

改完密码策略后,顺手把账号过期策略加上了。对长期不用的僵尸账号,直接锁定:

# 一键设置用户 must change password at next login chage -d 0 用户名 # 直接锁定长期不用的账号 usermod -L 用户名

4.2 启用 SSH 密钥认证并彻底关闭密码登录

密码再长也有被撞的可能,密钥认证则完全是另一套思路。客户端保存一把私钥,服务器保存对应的公钥,登录时用非对称加密做签名验证。攻击者没有私钥文件根本登不进来,暴力破解在密钥认证面前没有任何意义。

部署步骤:

在本地生成密钥对(客户端机器操作):

ssh-keygen -t ed25519 -a 100 -f ~/.ssh/某服务器_ed25519

-t ed25519指定使用椭圆曲线算法,安全性高且密钥短;-a 100是将 KDF 迭代次数设置为 100 轮,强行拖慢暴力破解的尝试速度。生成后把公钥上传到服务器:

ssh-copy-id -p 2022 -i ~/.ssh/某服务器_ed25519.pub 用户名@服务器IP

完成后在服务器端修改 SSH 配置:

PubkeyAuthentication yes PasswordAuthentication no ChallengeResponseAuthentication no UsePAM no

然后测试密钥登录,确认能顺利登录后,再重载 sshd:

sshd -t && systemctl reload sshd

这里有个容易踩的坑:先测密钥登录能通,再关密码认证。我上次给别人做安全加固时,对方远程操作,直接改了配置关掉密码认证,结果密钥没配好,他自己也登不进去了。最后只能通过云厂商管理终端进入恢复,折腾了半小时。正确的顺序一定是先传公钥-测密钥-再关密码。说道说道为什么UsePAM no——PAM 模块默认会额外做密码验证,关了它才能保证密码认证无效化。

4.3 部署 fail2ban 自动封禁恶意 IP

密码策略和密钥认证搞定后,总会有那么些 IP 不死心继续扫。与其每次人工封,不如让系统自己学会识别并封禁。fail2ban就是干这个的。

fail2ban的原理很简单:它持续监控日志文件,如果发现某个 IP 在设定时间内触发多次失败事件,就调用防火墙规则自动封禁该 IP,并在封禁期结束后自动解封。这相当于给 SSH 加了一层「免疫功能」。

安装和配置:

# CentOS yum install fail2ban -y # Ubuntu apt install fail2ban -y

在/etc/fail2ban/jail.local配置监控 SSH 服务的规则:

[sshd] enabled = true port = ssh filter = sshd logpath = /var/log/secure maxretry = 5 bantime = 3600 findtime = 600

每个参数的作用:

  • maxretry=5:10 分钟(findtime)内失败 5 次就触发封禁;
  • bantime=3600:封禁 3600 秒,也就是 1 小时;
  • filter=sshd:使用系统自带的 sshd 过滤规则;
  • logpath:指定日志路径,Ubuntu 上要改/var/log/auth.log。

启动之后我可以看到攻击 IP 开始陆陆续续进入封禁名单:

fail2ban-client status sshd

输出能看到:

Status for the jail: sshd |- Filter | |- Currently failed: 3 | |- Total failed: 26 `- Actions |- Currently banned: 4 |- Total banned: 12

我一直把bantime设为 3600 秒而不是永久封禁,原因是动态 IP 环境下,任何用户(包括你老板、客户、供应商的 IP)都有可能在触发阈值后误封。永久封禁一旦误伤,解封流程会非常痛苦。1 小时短封既能有效打断攻击,又能在误封后快速自愈。另外,我自己测试登录时经常连续输错密码,很容易触发规则把自己封掉,所以封禁时间拉长到 24 小时反而更麻烦。

4.4 防火墙和云安全组双重过滤

fail2ban自动封 IP 是应用层的机制,它的底座还是防火墙。我在系统防火墙层面也做了几件事,让针对性扫描难度更大。

首先是开防火墙端口白名单策略。如果这台服务器只对少数几个办公 IP 开放 SSH,那就用firewalld的富规则做来源限制:

firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="办公IP/24" port port="2022" protocol="tcp" accept' firewall-cmd --permanent --remove-service=ssh firewall-cmd --reload

只允许公司出口 IP 段访问 2022 端口,其他来源一律拒绝。对于单一管理员管理的服务器,这个方案最有效。如果服务器有多地办公人员需要 SSH 访问,至少也要做到按端口限制,而不是0.0.0.0/0全放。

云安全组同样可以设置。登录云平台控制台,在安全组规则里修改入站规则:

  • TCP 22 端口,来源0.0.0.0/0:移除;
  • TCP 2022 端口,来源办公IP段:保留。

这个动作的意义在于:云安全组是在虚拟化层拦截的,比系统防火墙更早发挥作用,攻击流量根本进不到你的 ECS 实例内部。两个防火墙叠加,攻击者连探测端口是否开放都会遇到困难,系统日志里失败记录都要少一大半。

5. 长期监控与事件复盘:安全不是一次性的

5.1 建立主动监控和告警

暴力破解不可能根除,你的服务器放在公网上,每天都会接收到各种扫描。真正有用的不是追求「零攻击」,而是做到「攻击早发现、失败不造成后果」。所以长期监控必须有。

我常用的是auditd配合 shell 脚本做关键文件监控,效果不错。先安装并启动审计服务:

apt install auditd -y systemctl enable auditd --now

然后添加关键文件的审计规则:

auditctl -w /etc/ssh/sshd_config -p wa -k sshd_config

这条规则的意思是:监控sshd_config的写入和属性变更,事件标记为sshd_config。一旦有修改动作,会记录在/var/log/audit/audit.log里。这样就算有人动了 SSH 配置,你也能在事后查到是什么时间点、被什么进程改的。

日志集中采集我也在推进。我的方案是给每台服务器装一个轻量日志采集代理,把/var/log/secure、/var/log/auth.log、/var/log/audit/audit.log实时推到集中日志系统。这样日志不会因为服务器被入侵而丢失,查询分析也更方便。

如果担心一开始配置太复杂,可以先做一个简单版本的监控脚本,每分钟检查一次失败登录次数,超过阈值就发告警:

#!/bin/bash fail_count=$(grep "Failed password" /var/log/secure | wc -l) if [ "$fail_count" -gt 200 ]; then echo "检测到高频暴力破解,当前失败次数: $fail_count" | mail -s "SSH 暴力破解告警" admin@example.com fi

告警渠道可以用邮件、企业微信机器人、短信。我个人的体会是短信优先级最高,邮件容易被忽略,微信机器人适合白天用。告警阈值要结合业务特点调,我这边设的是 10 分钟内 SSH 登录失败超过 50 次立即告警,平时不太会误报,真被刷的时候能第一时间通知到我。

5.2 事件复盘报告和后续改进

事件处理完,先别急着庆祝,下一步是写复盘报告。每次安全事故都有反复出现的点,写报告的过程能帮你把整个处理链路捋清楚。

复盘报告我按五个问题来组织:攻击源是什么、利用了什么薄弱点、影响范围多大、应急措施有哪些不足、后续如何防止类似事件。

我这次事件里暴露出两个重要问题:

第一是密码策略不够严:虽然 root 密码是随机长密码,但有几个运维同事共用的普通用户密码仍然偏弱,且从来没换过。这个漏洞排查时差点漏掉。事后强制改密并加上有效期,才真正补上。

第二是监控缺失:攻击刷了几百次日志,我之前毫不知情,直到看报警才发现。这说明部署集中监控和告警是长期安全的基础,不是可有可无。

另外记录一个经验:复盘时尽量不要只写自己的操作记录,要把时间线、关键日志证据、操作命令、处理结果全部附上。这一方面方便以后同类问题快速定位,另一方面如果有人需要向管理层汇报或与云厂商协同处理,材料拿得出手。

5.3 推荐的最低安全基线清单

如果对安全加固还没有成体系的方案,建议直接把下面这份最小化检查清单当模板,逐条对照落地:

检查项操作说明状态
SSH 密码认证已改为密钥认证,PasswordAuthentication no,已验证可正常登录待确认
root 远程登录PermitRootLogin no,日常使用普通用户 + sudo 切换待确认
密码复杂度pwquality.conf设置 minlen=16,启用数字/大小写/特殊字符组合待确认
账号清理逐项检查/etc/passwd,锁定所有不用的账号,删除空密码账号待确认
自动封禁fail2ban 配置maxretry=5, bantime=3600, findtime=600待确认
防火墙策略SSH 端口只对办公 IP 段开放,云安全组同步限制待确认
日志审计auditd 监控/etc/ssh/sshd_config等关键文件待确认
告警通知失败次数超过阈值自动推送告警到手机/即时通讯工具待确认

做完这一套,后面再遇到暴力破解就会轻松很多。攻击者扫一轮发现打不进来,自然会转向下一个目标。服务器安全不是买一个防入侵系统装上去就完事,它需要从账号、端口、认证方式、监控告警等多个维度一起构建,才能把风险压到一个可以接受的水平。

我在实际处理中还有一个体会:遇到攻击先别慌,先把事实搞清楚,再按「止损 -> 取证 -> 加固 -> 复盘」的顺序一步步走。这套方法论对任何一台服务器都适用。如果你现在的服务器还没有做密钥认证、密码策略也比较宽松,就从今天开始调整,别看不上这半小时的配置工作——真被爆破成功的时候,代价绝对不止这半小时。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询