
排查一台服务器“到底谁登过、什么时候登的、有没有人在试密码”很多人的第一反应是翻/var/log/secure或者journalctl -u sshd。但在 Linux 自带的用户管理工具里其实躺着一套更轻量、更快、几乎零依赖的登录审计入口last和lastlog。它们不需要额外装采集器不需要开审计服务只要系统还在正常写登录记录一条命令就能把“最近谁来过”拉成一张表。这篇文章就围绕这两个命令展开。核心判断先给出来last和lastlog不是“查一下登录记录”这么简单的两个查询命令它们背后对应着三个不同职责的系统数据库文件wtmp、btmp、lastlog理解这三个文件的边界比背参数重要得多。很多人用错last根本原因不是参数记不住而是压根不知道last读的是wtmp、lastb读的是btmp、lastlog读的是一个按 UID 索引的稀疏文件。读完之后你能得到什么一是能准确解读last和lastlog的输出知道每一列从哪来二是能在真实运维场景里做一次完整的登录审计包括从未登录账户排查、失败登录爆破源定位、轮转日志回溯三是能避开几个经典的坑比如误删wtmp、lastlog文件莫名膨胀到几个 G、新服务器上last直接报wtmp begins ...之外什么都没有。下面从最基础的文件职责讲起一路走到可复用的审计脚本和工程建议。文中所有命令都在标准 Linux 发行版的util-linux包内不需要额外安装软件涉及生产环境的操作会单独标注风险。1. 为什么登录审计总在出事之后才被想起日常运维里有个很典型的现象服务器跑得好好的没人会去看登录记录等到磁盘告警、账号异常、客户投诉“数据被人改过”才想起来要查“最近谁登进来了”。这时候打开终端敲last看到一屏密密麻麻的输出反而更懵了——哪一行是异常登录still logged in是什么意思为什么有几行显示gone - no logout问题的根源在于登录记录这类数据的特点是“平时没人看要看时必须看得懂”。它不像 CPU、内存、磁盘那样有监控曲线它是一堆文本记录没有被解读之前价值等于零。而last和lastlog恰好是把这些原始记录翻译成人能看懂的第一层工具。另一个容易被忽略的点是登录信息审计不只是安全团队的事。对普通开发者和运维来说它至少有三个高频用途。第一确认某台机器上是否有其他人在同时操作避免“我改的配置被别人覆盖了”这种扯不清的问题。第二排查账户是否被长期闲置做账号清理和最小权限收敛。第三定位失败登录的来源 IP判断是不是有人在对你做密码尝试。这里必须强调一个前提本文所有命令和脚本都应该在你有合法授权的服务器上执行。登录记录本身包含用户名、来源 IP、终端设备等敏感信息读取和导出都要遵守所在组织的安全规范。如果是排查安全事件正确做法是先保留证据复制日志文件、记录哈希再进行分析不要在原始文件上做任何写操作。所以这篇文章的定位很明确它不是man last的中文翻译而是把“登录审计”这件事拆成可执行的步骤告诉你每一步在读什么文件、判断依据是什么、结论怎么下、坑在哪里。2. last 与 lastlog 到底在读什么文件理解这两个命令必须先理解 Linux 的登录记账机制。系统并不会把“张三在 10 点 23 分从 192.168.1.5 登录 tty1”这句话直接写进日志文件而是用一种固定长度的二进制结构体utmp结构记录每次会话的开始和结束。这些结构体被追加写入三个不同的文件last系列命令就是把这些二进制结构体读出来反序列化成可读文本。2.1 三个数据库文件的职责边界先把这三个文件的关系理清楚后面所有命令的行为都能解释得通。文件路径记录内容对应命令典型权限/var/log/wtmp成功登录、登出、系统启动、关机、运行级别切换last0664 root:utmp/var/log/btmp失败登录尝试密码错误、用户不存在等lastb0600 root:utmp/var/log/lastlog每个用户最后一次登录的时间、来源、终端lastlog0664 root:utmp再补两个容易混淆的/var/run/utmp部分发行版是/run/utmp记录当前登录的会话是who、w、users的数据来源。它是实时的重启即清空。/var/log/faillog记录每个用户的失败登录次数和锁定状态配合faillog命令使用偏 PAM 账户锁定策略。这里的关键区别在于wtmp是事件流一条登录记一条、一条登出记一条可以按时间顺序回放lastlog是快照每个 UID 只保留最新的一条覆盖式写入。所以你想知道“这个月有谁登过”只能用last读wtmp你想知道“这个账号上一次登录是什么时候”用lastlog最快一条命令出结果。2.2 last 与 lastlog 的差异对比很多教程把这两个命令混着讲导致读者以为功能重叠。实际上从使用场景看它们的差别非常清晰。对比维度lastlastlog数据来源/var/log/wtmp默认/var/log/lastlog数据形态事件流水按时间倒序每用户一条按 UID 排序能查历史能只要wtmp没被轮转删除不能只保留最后一次能查失败登录不能需用lastb不能需用faillog输出行数与登录事件数成正比与系统 UID 数量成正比典型用途审计一段时间内的登录活动快速判断账户是否长期未使用一句话总结last回答“发生过什么”lastlog回答“最后一次是什么时候”。搞清楚这一点后面选命令就不会犹豫。3. 环境准备与前置检查last、lastb、lastlog都属于util-linux软件包几乎所有主流发行版默认安装。不需要编译、不需要服务、不需要配置文件这也是它在应急排查时特别好用的原因——哪怕系统已经被折腾得乱七八糟这几个命令大概率还能跑。执行前建议先做几项检查避免拿到错误的数据还当成结论。# 1. 确认命令是否存在以及来自哪个软件包 which last lastb lastlog rpm -qf $(which last) 2/dev/null || dpkg -S $(which last) 2/dev/null # 2. 确认三个记录文件是否存在及权限 ls -l /var/log/wtmp /var/log/btmp /var/log/lastlog # 3. 确认当前用户能否读取普通用户通常可读 wtmp、lastlog读不了 btmp id关于权限这里有个细节值得单独说。/var/log/btmp的权限通常是0600 root:utmp也就是只有 root 能读。这不是配置失误而是刻意的设计——失败登录记录里包含大量外部 IP 和被尝试的用户名暴露出去等于告诉攻击者哪些账号存在。所以普通用户执行lastb会遇到权限错误这是预期行为不是环境坏了。如果检查发现/var/log/wtmp不存在先别急着touch一个。空文件和老系统格式不兼容时last会输出wtmp begins ...之后什么都没有或者直接报格式错误。正确做法是确认logrotate配置里是否有针对wtmp的轮转规则以及是不是有人手动删过。# 查看 logrotate 主配置中与 wtmp/btmp 相关的段落 grep -A 6 -E ^/var/log/(wtmp|btmp) /etc/logrotate.conf 2/dev/null如果这条命令没有任何输出说明你的发行版把轮转规则放在了/etc/logrotate.d/下或者压根没有配置wtmp轮转部分精简镜像会这样。没有轮转意味着wtmp会无限增长长期运行下来几 MB 到几十 MB 都正常极端情况可能更大这一点在后面的排查章节会展开。4. last 命令核心用法拆解last的默认行为很简单读wtmp按时间倒序输出所有登录记录。但默认输出往往信息量过大实际使用中几乎总要配合参数。4.1 基本输出格式解读先看一条典型的输出把每一列的含义对齐。last -n 8预期输出大致如下具体内容以你的机器为准root pts/0 192.168.1.20 Mon Mar 10 09:12 still logged in deploy pts/1 10.0.3.55 Mon Mar 10 08:47 - 09:05 (00:18) root tty1 Sun Mar 9 22:31 - 23:02 (00:31) reboot system boot 5.10.0-28-amd64 Sun Mar 9 22:28 - 09:15 (10:47) deploy pts/0 10.0.3.55 Sun Mar 9 20:03 - 20:41 (00:38) root pts/0 192.168.1.20 Sun Mar 9 15:22 - 15:40 (00:18) wtmp begins Sun Mar 2 03:11:47 2025逐列解释第 1 列用户名。特殊值有reboot系统启动、shutdown关机、runlevel运行级别变化。第 2 列终端名。pts/N是伪终端SSH、图形终端里的终端窗口ttyN是本地虚拟控制台:0通常是图形界面登录。第 3 列来源。远程登录显示 IP 或主机名本地tty登录这一列为空。第 4 到 6 列登录时间与登出时间。括号内会话持续时长。最后一行wtmp begins ...这是wtmp文件中最早的一条记录时间也是你能回溯的时间下限。这里有个高频误读点still logged in表示会话还没有正常结束记录。它可能真的还在线也可能是会话异常断开比如网络中断、客户端崩溃导致系统没来得及写登出记录。不能仅凭still logged in就断定这个用户此刻在线要交叉验证who或w。这个区别在安全排查里非常重要后面会专门讲。4.2 常用参数组合last的参数不多但组合起来覆盖了大多数场景。# 只看最近 10 条 last -n 10 # 显示完整时间含年份和秒审计场景强烈建议加 last -F -n 20 # 自定义时间格式 last --time-format iso -n 20 # 显示完整用户名和域名避免被截断 last -w -n 20 # 显示来源 IP 而不是反解后的主机名 last -i -n 20 # 只看某个用户的登录历史 last deploy # 只看某个终端的历史 last pts/0 # 按时间范围过滤较新版本支持 last --since 2025-03-01 --until 2025-03-10关于-i这个参数值得多说一句。默认情况下last会尝试把来源 IP 反解成主机名反解过程依赖 DNS如果 DNS 慢或者不通命令会卡住好几秒甚至更久。在应急排查时这种卡顿很要命。所以实际使用中推荐始终带上-i直接显示 IP既快又准确。此外反解出来的主机名还可能被伪造的 PTR 记录误导-i也顺带规避了这个风险。-F参数同样建议形成习惯。默认输出省略年份跨年数据放在一起看会直接错乱——同一条Mar 10 09:12你根本不知道是今年还是去年。审计场景下时间必须精确到秒-F是必须的。4.3 last -x 与 last reboot-x参数会额外显示系统级事件包括关机、运行级别切换、runlevel记录。这个参数在分析“服务器在某个时间点为什么失联”时特别有用。# 查看系统启动记录 last reboot -F -n 10 # 查看关机记录 last shutdown -F -n 10 # 查看全部事件含运行级别切换 last -x -F -n 30last reboot的输出里最后一条如果是still running说明系统自那之后没有再重启过。这个信息可以用来快速确认机器是否发生过意外重启——如果运维说“没重启过”但last reboot显示昨天有一次那就值得追问了。一个实战经验判断服务器是否被异常重启last reboot比uptime更可靠。uptime只告诉你当前运行了多久last reboot会告诉你每一次重启的准确时间点能直接对应到变更窗口或告警时间。5. lastlog 命令核心用法lastlog的输出结构和last完全不同它按 UID 顺序列出系统上所有用户包括系统账户每行显示用户名、终端、来源、最后一次登录时间。lastlog | head -n 12预期输出大致如下Username Port From Latest root pts/0 192.168.1.20 Mon Mar 10 09:12:44 0800 2025 daemon **Never logged in** bin **Never logged in** sys **Never logged in** sync **Never logged in** games **Never logged in** man **Never logged in** deploy pts/1 10.0.3.55 Mon Mar 10 08:47:02 0800 2025这个输出有两个明显特征。第一系统账户大量显示**Never logged in**这是正常的daemon、bin、sync这些账号本来就不允许交互登录。第二普通用户的显示是“最后一次”而不是“所有记录”所以lastlog的行数和wtmp大小无关只和系统的 UID 数量包括 LDAP/SSSD 拉进来的用户有关。常用用法# 查看指定用户 lastlog -u deploy # 只显示 UID 范围内的用户 lastlog -u 1000-1100 # 只显示最近 N 天内登录过的用户老版本写法 lastlog -t 7 # 只显示超过 N 天未登录的用户 lastlog -b 30 # 清空某个用户的 lastlog 记录谨慎使用 lastlog -C -u testuser关于-t和-b不同版本的util-linux行为有差异新版本更推荐--since/--until配合日期使用。如果你的系统上-t 7报错或者行为不符合预期直接man lastlog看你这一版的参数说明不要照搬网上的写法。这也是本文不写死版本号的原因——参数在小版本之间确实会变。关于lastlog -C这里必须给出明确提醒它会清空指定用户的最后登录记录属于写操作。只应该在你有明确授权、且确实需要重置记录的场景下使用比如账号交接后清空痕迹。生产环境上随手执行等于破坏了审计证据。6. 完整实战一次登录审计的完整流程前面讲了单个命令现在把场景串起来。假设你接到一个任务某台对外提供服务的 Linux 主机需要确认最近一周的登录情况找出长期未使用的可登录账户并确认是否存在明显的密码尝试行为。6.1 场景定义与执行顺序这类任务有固定的执行顺序顺序错了会导致结论不可靠。推荐按下面四步走确认数据完整性和时间范围wtmp起点、轮转情况。拉取成功登录记录按用户和来源聚合。拉取从未登录/长期未登录的可交互账户清单。拉取失败登录记录按来源 IP 聚合排序。先做第 1 步的原因很实际如果wtmp昨天刚被轮转清空你后面所有“最近一周”的分析都是无源之水。先确认数据边界再下结论这是审计的基本纪律。6.2 分步执行命令第一步确认数据边界# 看 wtmp 最早记录时间同时确认文件大小和权限 last -F -n 1 | tail -n 1 ls -lh /var/log/wtmp /var/log/btmp /var/log/lastlog # 如果存在轮转文件一并纳入分析范围 ls -l /var/log/wtmp* 2/dev/null ls -l /var/log/btmp* 2/dev/null如果输出里能看到/var/log/wtmp-20250301这类轮转文件说明历史数据被切分了。last支持用-f指定文件可以把轮转文件逐个读一遍。# 读取轮转后的 wtmp 文件 last -F -f /var/log/wtmp-20250301 | head -n 20第二步成功登录按来源聚合# 提取最近登录记录中的来源列统计出现次数最高的前 10 个 last -i -F -n 200 | awk NF4 $3 ~ /^[0-9]\./ {print $3} | sort | uniq -c | sort -rn | head -n 10这段管道做了三件事awk过滤出第三列是 IP 格式的行剔除了reboot、tty本地登录这类没有来源的行sort | uniq -c做计数最后按次数倒排。输出能直接告诉你哪些 IP 登录最频繁。如果某个陌生公网 IP 出现次数异常高就是需要重点确认的对象。第三步找出可登录但从未登录的账户# 先列出所有允许交互登录的账户shell 为 bash/sh/zsh 等 awk -F: $7 ~ /\/(bash|sh|zsh|ksh)$/ {print $1} /etc/passwd /tmp/interactive_users.txt # 再列出 lastlog 中从未登录的账户 lastlog | grep Never logged in | awk {print $1} /tmp/never_users.txt # 求交集 comm -12 (sort /tmp/interactive_users.txt) (sort /tmp/never_users.txt)这个交集就是“允许登录但从来没登录过”的账户。这类账户在账号治理里属于典型的高风险项——存在、有 shell、但没人用一旦凭证泄露就是现成的入口。注意comm要求两个输入都已排序所以命令里用了进程替换加sort。第四步失败登录按来源聚合# 需要 root 权限 lastb -i -F -n 500 | awk NF4 $3 ~ /^[0-9]\./ {print $3} | sort | uniq -c | sort -rn | head -n 10如果lastb输出为空或者报权限错误先确认是不是 root 执行的再看/var/log/btmp是否存在。有些发行版的 sshd 配置里MaxAuthTries太小失败记录会被 PAM 层提前拦截导致btmp里记录不全这种情况要看journalctl -u sshd补齐。6.3 脚本化把审计流程固化成可复用脚本一次性的命令敲完就忘下次还得重来。把上面四步封装成一个脚本才是可持续的做法。#!/usr/bin/env bash # 文件路径/usr/local/sbin/login-audit.sh # 用途登录信息审计只读操作不修改任何系统文件 # 使用sudo /usr/local/sbin/login-audit.sh set -uo pipefail WTMP_FILE/var/log/wtmp BTPM_FILE/var/log/btmp REPORT_DIR/var/log/login-audit TS$(date %Y%m%d-%H%M%S) REPORT${REPORT_DIR}/audit-${TS}.txt mkdir -p ${REPORT_DIR} { echo echo 登录审计报告 生成时间: $(date %F %T) echo 主机: $(hostname) 内核: $(uname -r) echo echo echo ---- [1] 数据边界 ---- if [ -f ${WTMP_FILE} ]; then last -F -n 1 -f ${WTMP_FILE} | tail -n 1 ls -lh ${WTMP_FILE} else echo 警告: ${WTMP_FILE} 不存在无法分析成功登录记录 fi echo echo ---- [2] 最近 20 条登录记录 ---- last -i -F -n 20 || echo 无法读取 wtmp echo echo ---- [3] 登录来源 IP 频次 TOP10 ---- last -i -F -n 300 \ | awk NF4 $3 ~ /^[0-9]\./ {print $3} \ | sort | uniq -c | sort -rn | head -n 10 echo echo ---- [4] 可交互登录但从未登录过的账户 ---- awk -F: $7 ~ /\/(bash|sh|zsh|ksh)$/ {print $1} /etc/passwd | sort /tmp/.ia_interactive lastlog 2/dev/null | grep Never logged in | awk {print $1} | sort /tmp/.ia_never comm -12 /tmp/.ia_interactive /tmp/.ia_never || true echo echo ---- [5] 失败登录来源 IP 频次 TOP10 ---- if [ -f ${BTPM_FILE} ] [ -r ${BTPM_FILE} ]; then lastb -i -F -n 500 2/dev/null \ | awk NF4 $3 ~ /^[0-9]\./ {print $3} \ | sort | uniq -c | sort -rn | head -n 10 else echo 跳过: ${BTPM_FILE} 不存在或当前用户无读取权限需 root fi echo echo echo 报告结束 } | tee ${REPORT} echo echo 报告已保存至: ${REPORT}这个脚本有几个设计考虑值得说明。第一全程只读tee把结果同时打到终端和文件不做任何删除或清空动作。第二所有可能失败的命令都加了|| true或2/dev/null避免因为某一段没数据导致整个脚本中断——审计脚本最怕的是中途退出只出一半报告比不出更坑。第三报告文件名带时间戳重复执行不会覆盖历史结果方便横向对比。运行方式sudo chmod 750 /usr/local/sbin/login-audit.sh sudo /usr/local/sbin/login-audit.sh7. 运行结果验证与结论判断脚本跑完之后重点不是看输出有多长而是看几个关键判断点。下面这张表是实际审计时最常用的判断依据。观察到的现象通常意味着什么下一步动作大量陌生公网 IP 出现在成功登录记录里可能存在凭证泄露或共享账号核对业务需求确认账号归属必要时改密并限制来源lastb中某个 IP 失败次数远高于其他存在密码尝试行为结合防火墙/安全组做访问控制检查该账号是否已被锁定可交互账户中出现Never logged in闲置账号属于收敛对象确认归属后禁用 shell 或锁定账户last显示gone - no logout会话异常中断未写登出记录结合who/journalctl判断是否仍有残留进程wtmp begins时间就是今天wtmp刚被轮转或清空往前找轮转文件否则历史分析无依据still logged in但who里没有会话已断开但记录未更新属于正常现象不要误判为在线关于最后两种情况需要展开讲一下因为这是最容易得出错误结论的地方。gone - no logout的含义是wtmp里记到了这次登录的开始时间但对应的登出记录没有写进去。常见原因是客户端直接断网、SSH 连接被 kill、系统负载过高导致会话进程异常退出。它不等于“有人还在操作”也不等于“被入侵”。正确的做法是查who看当前是否有该会话再查ps -ef看有没有残留的 shell 进程。still logged in同理。系统认为这个会话还没结束但实际连接可能早就断了。所以判断“当前谁在线”永远以who、w为准last只能作为辅助。这个边界如果搞混很容易在排查时得出“有人在偷偷登录”的错误结论反而制造混乱。至于wtmp begins显示的日期离今天很近也不一定是异常。如果配置了按月轮转且只保留一份月初看到wtmp begins是 1 号之后的时间是完全正常的。判断依据应该是轮转配置而不是日期本身的新旧。8. 常见问题与排查表实际使用中踩的坑基本集中在权限、文件、格式、参数四类。下面这张表覆盖了最常见的情况。问题现象可能原因排查方式解决方案last: /var/log/wtmp: No such file or directorywtmp被手动删除或从未生成ls -l /var/log/wtmp不要手动touch检查 logrotate 配置重启一次相关服务或等待系统重新写入lastb: /var/log/btmp: Permission deniedbtmp权限为0600 root:utmpls -l /var/log/btmp用sudo执行不要为了图方便改成 644lastlog输出为空或只有表头lastlog文件被清空或系统使用 SSSD 且记录在别处ls -lh /var/log/lastlog确认是否有 PAM 模块接管检查pam_lastlog配置ls -l /var/log/lastlog显示大小几个 G稀疏文件按 UID 偏移写入大 UID 会撑大显示大小du -h /var/log/lastlog对比实际占用属正常现象无需处理若du也很大才需要关注last执行后卡住几秒反解来源 IP 的主机名时 DNS 超时加-i试试是否变快养成加-i的习惯或检查 DNS 配置last时间没有年份跨年数据混乱默认时间格式省略年份观察输出加-F或--time-format isolast --since报参数错误当前util-linux版本不支持last --help查看参数列表改用-n结合awk过滤或升级util-linuxwtmp持续增大占用磁盘未配置轮转grep wtmp /etc/logrotate.conf补充轮转规则参考下一节配置重启记录缺失系统强制断电未走正常关机流程last -x对比journalctl -b属预期行为wtmp无法记录硬断电lastlog中大量系统账户显示Never logged in系统账户本就不允许登录检查/etc/passwd中的 shell无需处理只关注 shell 为bash/sh的账户其中“稀疏文件”这一条特别值得展开。/var/log/lastlog的存储结构是“以 UID 乘以结构体大小作为文件偏移量”每个用户一条记录。这意味着如果系统上存在 UID 为 1000000 的用户常见于 LDAP 或容器环境映射文件逻辑大小就会达到1000000 × 结构体大小ls显示出来可能是几十 GB但实际占用磁盘可能只有几十 KB。看到这个现象不要慌更不要删文件用du -h确认实际占用即可。真正需要处理的是 UID 规划不合理的问题而不是文件本身。另一个常见的误区是“清空wtmp就能释放空间”。确实能但代价是丢失全部登录历史。正确做法是配置 logrotate让系统按周期轮转并保留合理份数既控制体积又保留审计窗口。9. 最佳实践与工程建议聊完命令和排错最后说说怎么把这件事做扎实。登录审计的价值不在于“会敲命令”而在于形成一套稳定的、可重复的、有据可查的流程。9.1 日志轮转配置要显式确认很多发行版的默认配置里wtmp和btmp的轮转规则是写在/etc/logrotate.conf主文件里的内容大致如下# 文件路径/etc/logrotate.conf /var/log/wtmp { missingok monthly create 0664 root utmp minsize 1M rotate 1 } /var/log/btmp { missingok monthly create 0600 root utmp rotate 1 }注意rotate 1表示只保留一份历史文件。对普通业务机够用但如果你所在的环境有合规要求比如需要保留 180 天登录记录这个配置明显不够。调整时不要直接改主文件更推荐在/etc/logrotate.d/下新建独立配置避免系统升级时被覆盖。# 文件路径/etc/logrotate.d/login-audit /var/log/wtmp { missingok monthly create 0664 root utmp rotate 12 compress delaycompress } /var/log/btmp { missingok monthly create 0600 root utmp rotate 12 compress delaycompress }rotate 12按月轮转即保留一年compress配合delaycompress保证最新一份不压缩、方便直接用last -f读取。改完之后用logrotate -d /etc/logrotate.d/login-audit做一次 dry-run确认没有语法问题再让它生效。这里要提醒一句不要用cat /dev/null /var/log/wtmp这种“清空”手法。它确实能让文件瞬间变空但会同时抹掉全部审计证据而且没有轮转归档出事后什么都查不到。生产环境上做这类操作前务必确认你有授权、有备份、有回滚方案。9.2 审计结论要交叉验证单一数据源永远不够。last说某人在线who说没有这时候要信who。lastb显示大量失败登录但journalctl -u sshd里没有对应记录说明失败可能来自本地su或sudo而不是 SSH。推荐的交叉验证组合# 当前在线会话以这个为准 who -a # 最近的系统级事件 last -x -F -n 20 # SSH 服务的详细记录如果使用 systemd-journald journalctl -u sshd --since 7 days ago --no-pager | tail -n 50 # 当前进程中的登录 shell ps -ef | grep -E sshd:.*|login | grep -v grep把这几个来源对照着看结论的可信度会高很多。只看一个来源就下判断是审计里最容易犯的错误。9.3 账号治理要形成闭环登录审计的最终目的不是“查出来一堆记录”而是推动账号治理。具体来说有三个动作可以固化下来。第一定期清理Never logged in的可交互账户。做法不是直接删用户会留下孤儿文件而是先usermod -L锁定观察一个周期确认无人使用后再userdel。删除前记得确认该用户是否有定时任务、是否有正在运行的进程。第二限制登录来源。如果业务允许在 SSH 配置或防火墙层面收敛来源网段从源头上减少异常登录的可能性。这一步比事后查日志有效得多。第三把审计脚本挂到定时任务里每周生成一份报告存档。这样即使wtmp被轮转你手里还有历史快照。# 文件路径/etc/cron.d/login-audit # 每周一凌晨 3 点执行登录审计输出保存到 /var/log/login-audit/ 0 3 * * 1 root /usr/local/sbin/login-audit.sh /dev/null 219.4 权限与合规边界最后必须强调权限边界。/var/log/btmp保持0600 root不是保守而是必要。它记录了所有失败登录尝试的用户名和来源泄露出去等于给攻击者提供了一份“哪些账号存在”的字典。同理审计报告文件本身也应限制权限建议chmod 640并归属 root。如果需要把审计数据交付给其他团队优先交付聚合后的统计结果频次、时间段分布而不是原始登录记录。原始记录包含用户名和 IP属于敏感信息交付前要确认对方有对应的授权和数据使用规范。10. 几个需要提前说清的边界写到这里把几个容易被误解的边界集中澄清一下避免读者在实际使用中走弯路。边界一last不是万能的审计工具。它只记录通过 PAM 会话机制建立的登录。如果攻击者通过其他方式获得执行权限比如 Web 应用漏洞直接反弹 shell根本不会在wtmp里留下任何记录。所以登录审计只能覆盖“正常登录路径”不能替代应用层日志和主机入侵检测。边界二记录可以被篡改。wtmp、btmp、lastlog都是普通文件有 root 权限就能改。它们不是不可篡改的审计日志。对安全要求高的环境应该把日志实时转发到独立的日志服务器本地文件只作为快速排查的辅助。边界三容器环境里这些命令基本失效。容器共享宿主机内核但没有独立的登录会话/var/log/wtmp通常是空的或者不存在。在容器里查登录记录没有意义要查就去宿主机查。边界四SSSD/LDAP 用户的lastlog行为可能不同。部分环境下pam_lastlog对远程目录用户不写lastlog导致这些用户在lastlog里一直显示Never logged in但实际天天在登录。遇到这种情况用last交叉验证不要直接据lastlog下结论。把这几条边界记住基本就不会出现“用错工具得出错误结论”的情况了。last和lastlog的价值在于快和轻在于出问题第一时间能拉出一张表来看它们的局限也很明确需要和其他日志源配合使用。如果你手上正好有一台长期运行的服务器不妨现在就执行一遍last -F -n 30和lastlog | grep -v Never logged in看看输出里有没有你不认识的账号或 IP。这个动作只需要十几秒但很多时候问题就是在这十几秒里被发现的。