
很多人看到服务器里刷出大段Failed password日志第一反应就是“被暴力破解了”。这个判断方向没错但不够严谨。登录失败事件背后可能是恶意扫描、密码错误、账户锁定、SSH 配置异常甚至只是网络抖动导致的认证中断。如果不加区分地对着日志一刀切很容易误封正常用户或者漏掉真正的风险。这篇文章我不会讲太多空泛的理论就按一线排查的思路来写登录失败事件到底记录在哪、怎么快速定位、如何区分攻击和误操作、怎样做成自动化分析以及我在实际运维里踩过的坑和排查技巧。适合刚接手 Linux 服务器的新人也适合已经会看日志但想系统梳理一遍的运维同学。1. 登录失败事件从哪里来先把日志源头摸清楚1.1 不同发行版的日志文件差异Linux 下记录登录认证信息的日志最常见的是auth.log和secure但不同发行版路径不太一样这也是新手第一次排查时最容易卡住的地方。Debian、Ubuntu 系/var/log/auth.log包含 sshd、sudo、login、su 等认证信息。RHEL、CentOS、Rocky 系/var/log/secure作用类似。极简系统或容器可能没有传统 syslog 文件只有 systemd-journald要用journalctl查看。除此之外还有一类二进制日志文件专门记录登录失败也就是/var/log/btmp。这个文件不是普通文本不能直接cat或者tail需要用lastb命令读取。如果系统里没有 btmp通常是日志轮转把旧文件压缩成了btmp.1.gz之类的归档。文件/命令作用常见路径auth.log记录认证事件/var/log/auth.logsecure与 auth.log 对应的 RHEL 系日志/var/log/securebtmp记录失败登录的二进制日志/var/log/btmplastb读取 btmp 内容对应 btmpjournaldsystemd 统一日志通过 journalctl 读取faillock查看账户锁定状态由 pam_faillock 生成这里要特别提醒很多系统默认按周轮转日志/var/log/auth.log里可能只有最近一周的记录。如果你需要保留更长的登录失败历史最好把logrotate的保留轮数调大或者把日志转发到远程日志服务。否则等到真出事时历史记录已经被清掉了排查起来很被动。1.2 一行登录失败日志里到底藏了哪些信息日志只有会读才有价值。我用一条常见的 sshd 失败记录举例Mar 10 08:23:41 srv-web01 sshd[2431]: Failed password for root from 203.0.113.10 port 52310 ssh2逐个字段拆开看Mar 10 08:23:41事件时间。srv-web01主机名。sshd[2431]产生日志的进程名和 PID。Failed password for root认证失败类型这里明确是密码错误。from 203.0.113.10来源 IP。port 52310客户端源端口。ssh2SSH 协议版本。还有一种常见格式Mar 10 08:23:42 srv-web01 sshd[2431]: Failed password for invalid user admin from 198.51.100.7 port 40123 ssh2多了一个invalid user admin意思是“尝试登录一个系统里根本不存在的用户 admin”。这是典型的扫描特征因为攻击者不知道系统有哪些真实用户只能批量试。注意区分invalid user和正常用户名错误前者往往更值得关注。如果看到Connection closed by authenticating user root 203.0.113.10 port 52310 [preauth]这说明连接在认证完成之前就断开了未必是密码错误可能是密钥交换超时、客户端提前关闭也可能是有人在用扫描工具批量探测。2. 快速定位登录失败事件命令组合拳2.1 用 grep 和 awk 把日志拉出来看第一步就是把失败记录单独拎出来。在 Debian/Ubuntu 上grep Failed password /var/log/auth.log | tail -n 50在 RHEL/CentOS 上把路径换成/var/log/secure即可。这个命令输出的是最原始的失败记录先看时间、IP、用户名心里有个大概印象。如果日志量特别大直接tail不够建议按时间窗口过滤。比如看最近一小时内的失败登录grep Failed password /var/log/auth.log | awk $1 $2 $3 Mar 10 08:00:00这里$1是月份$2是日期$3是时间通过字符串比较来过滤。对大多数日志场景够用但更精确的做法是用journalctl --since。统计每个来源 IP 的失败次数最常用的是一行 awkgrep Failed password /var/log/auth.log | grep -oE from [0-9.] | awk {print $2} | sort | uniq -c | sort -rn | head -n 20这条命令做的事情先从日志里筛出Failed password行然后提取from后面的 IP再统计次数并排序。看输出时如果某几个 IP 的次数明显高于其他 IP基本就是扫描源。2.2 用 lastb 查看二进制登录失败记录文本日志可能被清理但 btmp 通常还在。lastb专门读取/var/log/btmp输出效果和last类似sudo lastb -n 20输出示例root ssh:notty 203.0.113.10 Mon Mar 10 08:23 still logged in admin ssh:notty 198.51.100.7 Mon Mar 10 08:24 gone - no logoutlastb -n 20只显示最近 20 条。如果要用 IP 统计可以把lastb的输出再次导入awksudo lastb | awk {print $3} | sort | uniq -c | sort -rn | head这里$3是来源 IP。lastb需要 root 权限否则可能提示权限不足。还有一点btmp 文件记录的内容也受轮转影响如果lastb显示为空可以看看/var/log/下有没有btmp.1或btmp.1.gz用zcat /var/log/btmp.1.gz | lastb -f -读取。2.3 用 journalctl 统一收口如果你用的是 CentOS 7 以上或者比较新的 Ubuntusshd 的日志可能走的是 systemd-journald。这时候传统/var/log/secure和/var/log/auth.log仍然存在但 journald 里的信息更全查看方式也更灵活。只看 sshd 服务的日志journalctl -u ssh --since 1 hour ago在 Ubuntu 上服务名可能是sshCentOS 上可能是sshd可以先journalctl -u sshd --since 1 hour ago | grep Failed passwordjournalctl 的--since支持2025-04-01 00:00:00、yesterday、1 hour ago这些写法比手工过滤auth.log方便得多。如果系统同时开启了 rsyslog 和 journald两条链路都在记内容基本一致不用重复处理hash。2.4 查询账户锁定状态如果登录失败次数触发了系统账户锁定策略用户会发现自己明明输对密码也登不进去。这时候要查 PAM 的锁定记录。用faillock命令faillock --user root输出会显示失败次数、最后失败来源、锁定窗口。如果确认账户被锁可以手动清空faillock --user root --reset注意不同系统配置的 PAM 模块不同有些老系统用的是pam_tally2那就要用pam_tally2 --user root不要凭记忆硬套命令先看/etc/pam.d/sshd或/etc/pam.d/login里配置的是哪个模块。3. 分清真正攻击还是用户误操作3.1 典型暴力破解的特征画像看到失败日志不要慌先判断性质。典型的自动化暴力破解通常有这几种特征来源 IP 集中在少数几个地址同一 IP 在短时间内反复尝试。尝试的用户名非常杂从root、admin、test到oracle、ubuntu都有明显是在撞库。间隔非常有规律比如每秒或每几秒固定发一次认证请求。大量出现invalid user说明攻击者在盲猜用户名。我用一个实际观察到的数据来举例。某台测试机上一个 IP 在 24 小时内产生 3820 次Failed password尝试的用户名超过 150 个。这说明它连系统里有哪些账户都不知道纯粹是拿字典在跑。对这类行为可以直接在防火墙层面封掉来源 IP。3.2 用户误操作的几种典型表现误操作和攻击的差别其实很明显只要不戴“攻击滤镜”看日志就能分辨。最常见的情况是用户在输密码时连续敲错几次日志里出现同一个内网 IP 对同一个用户的几连败然后紧接着成功登录。这种情况来源 IP 一般是内网地址记录很少时间上有明显的“人操作”节奏不会像自动扫描那样均匀。还有一种是 SSH 密钥权限问题。客户端配了密钥但服务端不认或者客户端本地密钥文件权限不对认证初期就断开。日志里表现为Connection reset by 192.168.1.20 port 51234 [preauth]这种没有Failed password关键字容易被忽略。用户会反复重试每次都在几秒内断开。所以排查登录问题时不能只看Failed password也要看Connection closed、Connection reset、Timeout这些认证完成前的异常断开记录。3.3 把“失败”和“成功”关联起来看只看失败可能漏掉真正的入侵。攻击者如果已经用暴力破解拿到了某个弱密码账户他甚至不需要继续制造失败记录。所以在分析时要把btmp失败和wtmp成功结合起来。先用last -n 30看最近成功登录记录重点确认三件事在登录失败集中的时间段里是否有来自同一个来源 IP 的成功登录。成功登录所使用的用户名是否是弱密码账户。成功登录之后是否有异常的命令执行记录比如从普通用户切换为 root。如果某个 IP 先产生几千条失败记录然后突然出现一条成功登录那么可以基本断定账户已经被攻破至少需要立即修改密码、检查系统进程和 cron 任务。3.4 用时间线和用户名分布缩小可疑范围把失败记录按小时统计成一条曲线观察波峰。如果波峰出现在凌晨且来源 IP 是境外地址基本可以判定是扫描。如果失败发生在工作时间且用户名集中在某几个真实账户上可以优先怀疑内部人员操作问题。按用户名聚合的命令也很好用grep Failed password /var/log/auth.log | grep -oE for (invalid user )?[a-zA-Z0-9_.-] | awk {print $NF} | sort | uniq -c | sort -rn | head输出会显示哪个用户名被尝试的最多。正常暴力破解里root一定是高频但如果你的系统已经禁用了 root SSH 登录那root失败再多也只是噪音真正要关注的是真实存在且允许登录的账户。4. 自动化分析与安全联动4.1 写一个轻量级统计脚本手动执行命令适合临时排查但如果每一天都要看一遍就太累了。我在实际工作中习惯写一个几十行的统计脚本输出当天登录失败排名前 20 的 IP 和用户名每周跑一次。#!/bin/bash LOG_FILE/var/log/auth.log YESTERDAY$(date -d yesterday %b %d) echo 近一天登录失败统计 echo --- 按来源IP --- grep $YESTERDAY $LOG_FILE | grep Failed password | grep -oE from [0-9.] | awk {print $2} | sort | uniq -c | sort -rn | head -n 20 echo echo --- 按用户名 --- grep $YESTERDAY $LOG_FILE | grep Failed password | grep -oE for (invalid user )?[a-zA-Z0-9_.-] | awk {print $NF} | sort | uniq -c | sort -rn | head -n 20如果日志文件路径不同改成/var/log/secure即可。用date -d yesterday生成格式和日志月份一致的条件字符串比写死日期更省心。这个脚本输出的内容已经足够做日常安全巡检。邮件通知可以做但不要在脚本里写死邮箱账号密码建议用系统mail命令配合本地邮件转发或者直接写入监控系统。4.2 和 fail2ban 联动实现自动封禁只看日志不能挡住后续攻击所以生产环境建议配置 fail2ban。核心配置在/etc/fail2ban/jail.local我不会把所有参数都改一遍只动这几个关键项[sshd] enabled true port ssh filter sshd logpath /var/log/auth.log maxretry 5 findtime 600 bantime 3600参数含义maxretry在findtime时间段内允许的最大失败次数超过就封。findtime统计窗口单位秒600 表示 10 分钟。bantime封禁时长单位秒3600 表示 1 小时。这个数值不是越大越好。maxretry设置成 3 会容易误伤手滑输错密码的同事设置成 10 又给攻击者留了太多尝试机会。我一般习惯maxretry 5、findtime 600、bantime 3600如果某个 IP 反复被封再人工决定要不要永久封禁。fail2ban 还会在封禁时写日志位置通常在/var/log/fail2ban.log。配合grep Ban /var/log/fail2ban.log能看到封禁记录。如果系统里有大量来自内网的用户一定要把内网 IP 段加入ignoreip否则可能把正常办公网段封掉。4.3 不要只把日志存在本地攻击者如果拿到了 root 权限第一个动作往往不是删文件而是把日志里和自己相关的记录清掉。所以任何靠本地日志的检测方案都有盲区。我建议至少做一件事把 auth/secure 日志实时转发到另一台独立的日志服务器。rsyslog 的配置很简单在被监控机器上往/etc/rsyslog.d/remote.conf里加auth.* 192.0.2.100:514对方服务器上打开 UDP 514 端口接收即可。生产环境建议走 TLS 或至少限制来源 IP。有了远程日志副本即使本机日志被清理也能从日志服务器查出攻击路径。另外logrotate配置要检查一下。默认配置下 auth.log 可能只保留 4 周攻击记录如果发生在两个月前早就没了。我习惯把/etc/logrotate.d/rsyslog里的rotate 4改成rotate 26保留半年以上同时开启压缩。5. 常见问题与排查技巧实录5.1 lastb 没有输出可能是二进制文件没生成有些精简系统默认没有 btmp 文件lastb会提示无法打开。这时候用touch /var/log/btmp创建即可但要注意权限必须为root:utmp 660sudo touch /var/log/btmp sudo chown root:utmp /var/log/btmp sudo chmod 660 /var/log/btmp如果文件存在但lastb输出为空看看是不是文件被轮转成了btmp.1.gz。用sudo zcat /var/log/btmp.1.gz | lastb -f -可以读取旧的失败记录。不要一上来就怀疑是系统没记录先检查轮转文件。5.2 日志时间混乱本地时间和 UTC 的坑SSH 登录日志默认记录的是系统本地时间。如果你的服务器时区设置为 UTC而业务团队在其他时区排查时容易觉得“攻击时间对不上”。统一处理方法是让所有日志都按 UTC 记录再在展示层转换时区。timedatectl可以查看当前设置timedatectl如果显示Universal time和Local time有差异先确认你按哪个时区去分析。不要为了迁就个人习惯频繁修改系统时区日志时间轴最容易因为时区修改而出现乱序在关联多台服务器日志时会非常痛苦。5.3 Failed password 和 Invalid user 的解读差异日志里Failed password for root表示 root 用户真实存在只是密码不对。如果 root 本身已经禁止 SSH 登录这个记录代表攻击者根本没找到可登录账户威胁不大。Failed password for invalid user guest表示系统里不存在 guest 这个账户同样属于扫描。但有一种情况要注意如果入侵者已经创建了隐藏账户然后尝试登录这个新账户也会出现类似记录。所以遇到不认识的用户名不能只判断“不存在”还要用getent passwd 用户名验证是否真的不存在。日志关键字可能含义优先级Failed password for rootroot 账户密码错误或尝试 root 登录中Failed password for invalid user xxx尝试不存在的用户名中高Invalid user xxx from IP同上另一种记录格式中高Connection closed by authenticating user认证过程中连接中断低Received disconnect from IP连接被服务端/客户端关闭低error: maximum authentication attempts exceeded客户端尝试次数超限中5.4 账户锁定策略要平衡安全性配置了登录失败锁定策略后攻击者会被限制但正常用户也可能被锁。我之前遇到过一台服务器因为某个运维连续输错 6 次密码触发了 pam_faillock 锁定结果当天晚上值班同事要紧急连服务器怎么都登不进去。后来调整策略只对 SSH 登录做限制而且不锁 root只锁普通用户。/etc/security/faillock.conf里可以配置deny 5 unlock_time 900另外unlock_time不要设置成永久锁。有些团队图省事把失败次数设成 3、锁定时间设成永久结果每次有人改密码后忘通知同事就只能去控制台解锁应急效率反而降低。5.5 登录失败日志和磁盘空间的关系最后提一个不容易想到的问题日志量过大也会拖垮系统。曾经有一台服务器被暴力破解扫描/var/log/auth.log一天涨了十几 GB最终导致根分区写满服务全部异常。文件多大算异常我建议用这个方式快速确认ls -lh /var/log/auth.log /var/log/secure 2/dev/null正常业务量下 auth.log 每天增长应该在几十 MB 以内。如果出现单日几百 MB多半是异常扫描或日志死循环。处理办法是先封掉攻击来源再压缩归档当前日志不要直接删除保留现场对后续溯源很重要。5.6 几个能提高效率的小习惯分析登录失败事件时我习惯先把命令和结果记录到本地文本或者直接写入运维文档。因为排查现场思路容易乱把中间结果记下来后面写报告或二次排查时能省很多事。另外日志里大量出现sudo: Failed password for user root和sshd失败不要混在一起统计。sudo 失败通常发生在本地终端或已认证会话中和 SSH 暴力破解性质完全不同。分析前先用关键字区分服务来源。如果你要定期排查多台服务器单机命令效率太低可以考虑批量执行工具但不要把所有服务器日志直接拉回来再处理更好的方案是让日志集中到一台服务器上所有分析都针对远程日志副本进行。这次先分享到这儿。我在处理过的案例里最深刻的体会是登录失败事件百分之百会出现关键不是消灭失败日志而是建立一套从发现、分析到处置的稳定流程。先看清楚失败是来自扫描、误操作还是真正被入侵再决定封禁还是放行尤其是别一看到多个失败 IP 就手动iptables封一堆导致正常服务被波及。最实用的一个小技巧看到Failed password后别急着去数次数先跑一条grep -c看总量级再按 IP 聚合这样能快速判断值不值得继续深挖。