news 2026/10/24 4:22:14

Linux登录审计:last、lastlog与wtmp/btmp实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux登录审计:last、lastlog与wtmp/btmp实战

排查一台服务器“到底谁登过、什么时候登的、有没有人在试密码”,很多人的第一反应是翻/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 30

last 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 场景定义与执行顺序

这类任务有固定的执行顺序,顺序错了会导致结论不可靠。推荐按下面四步走:

  1. 确认数据完整性和时间范围(wtmp起点、轮转情况)。
  2. 拉取成功登录记录,按用户和来源聚合。
  3. 拉取从未登录/长期未登录的可交互账户清单。
  4. 拉取失败登录记录,按来源 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 'NF>=4 && $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 'NF>=4 && $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 'NF>=4 && $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 'NF>=4 && $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.sh

7. 运行结果验证与结论判断

脚本跑完之后,重点不是看输出有多长,而是看几个关键判断点。下面这张表是实际审计时最常用的判断依据。

观察到的现象通常意味着什么下一步动作
大量陌生公网 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执行,不要为了图方便改成 644
lastlog输出为空或只有表头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 iso
last --since报参数错误当前util-linux版本不支持last --help查看参数列表改用-n结合awk过滤,或升级util-linux
wtmp持续增大占用磁盘未配置轮转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 2>&1

9.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。这个动作只需要十几秒,但很多时候,问题就是在这十几秒里被发现的。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/24 4:22:14

Linux chmod 权限全解:755/644、目录权限与故障排查

chmod 是 Linux 日常运维里出现频率最高的命令之一&#xff0c;也是最容易被"背答案"背坏的命令之一。很多人能脱口而出 755、644、777&#xff0c;但一旦遇到"权限给了 777 还是提示 Permission denied""普通用户删不掉别人的文件""脚本明…

作者头像 李华
网站建设 2026/10/24 4:20:35

Unity uGUI ScrollRect分页吸附与循环列表优化

简介&#xff1a;Viwepager.zip 是一份基于 Unity3D 引擎的图片轮播完整工程&#xff0c;面向已掌握基础操作、希望深入界面与动画实现的学习者和独立开发者&#xff0c;可用于图片集展示、产品信息轮播等交互界面场景。工程围绕 UI Canvas 搭建图片容器与切换按钮&#xff0c;…

作者头像 李华
网站建设 2026/10/24 4:20:26

VC读取TXT按行显示源码:MFC编码处理与大文件日志查看

简介&#xff1a;这份VC源码包面向刚接触C文件操作与MFC工程组织的开发者&#xff0c;围绕“读取TXT文件并按行显示”给出可直接对照学习的完整示例&#xff0c;覆盖文件打开、逐行读取、控制台输出及资源释放等关键环节。压缩包共38个文件&#xff0c;约1.87MB&#xff0c;以6…

作者头像 李华
网站建设 2026/10/24 4:19:36

XGBoost时序预测实战:从特征工程到滚动回测的完整工程

简介&#xff1a;这份资源面向时间序列预测与机器学习的入门及进阶学习者&#xff0c;用Xgboost算法打通从数据分析、特征工程到模型训练、保存与预测评估的完整链路&#xff0c;可应用于金融、气象、股票等趋势预测场景。压缩包共3个文件&#xff0c;以2个Python脚本和1个CSV数…

作者头像 李华
网站建设 2026/10/24 4:18:32

Tesseract离线中文OCR:安装调参、图像预处理与置信度闸门

简介&#xff1a;面向需要在本地部署文字识别能力的开发者与办公自动化用户&#xff0c;这份资源提供Tesseract-OCR的完整安装包及中文语言包&#xff0c;可用于扫描文档、图片文字提取、批量数据录入等场景&#xff0c;也适合研究OCR训练流程的技术人员。压缩包共724个文件、约…

作者头像 李华
网站建设 2026/10/24 4:17:34

OpenCV图像拼接实战:从特征匹配到多频段融合的Python流水线

简介&#xff1a;全景拼合图片算法资料包面向希望掌握全景拼接与图像融合的开发者、视觉方向学生及图像处理爱好者&#xff0c;围绕OpenCV Stitcher调用、PhotoShop PhotoMerge脚本及其中英文专利文档展开&#xff0c;并补充手动微调代码&#xff0c;兼顾理论文档与工程实践&am…

作者头像 李华