Linux系统日志实战:从journald到安全审计的排查与防御指南
2026/9/16 2:33:48 网站建设 项目流程

半夜两点被值班电话叫醒,说线上服务全挂了。我揉着眼睛连上跳板机,第一件事不是去看监控大屏,而是先打开/var/log/messagesjournalctl -xe。为什么?因为监控只告诉你“什么挂了”,日志才能告诉你“为什么挂”。干运维这些年,我越来越确信一件事——Linux 系统日志就是一台机器的病历本和黑匣子,故障排查、安全审计、渗透复盘,哪样都离不开它。

这篇文章我不打算写成命令手册的堆砌,而是想把自己实际排障、做安全加固、整理攻击链路的经验串起来,把 Linux 日志体系的底层逻辑、高频排查路径、以及容易被忽略的坑一次性讲透。适合刚入门想要建立排查思路的新人,也适合有一定经验但想把日志用得更系统的运维和安全工程师。

1. 先盘清楚家底:Linux 日志到底存在哪,又是谁在写

很多人一上来就背日志路径,这个在案发时根本没用。你得先理解日志的产生源头和流转路径,才能知道在什么场景去哪里找。

1.1 日志的三大源头:内核、系统服务、用户态应用

Linux 下的日志从来源上分,主要就三路:

  • 内核日志:由内核自己产生,包括硬件驱动报错、文件系统错误、OOM 杀进程、网络栈异常等。最早统一由klogd接管,现在基本走/dev/kmsg,最后进入journald或者/var/log/dmesg
  • 系统服务日志:sshd、crond、rsyslog、NetworkManager 这些由 systemd 托管或传统 SysV 管理的服务,是日常排障最常翻的东西。
  • 用户态应用日志:Nginx、MySQL、Java 应用这些跑在用户态的进程自己写的日志,多半不走系统日志通道,而是写到各自的日志目录里。

记住上面的分类,你在排查时就会顺着问三个问题:是内核有问题,还是系统服务有问题,还是应用自己有问题?方向对了,定位就快。

1.2 常用日志位置速查表

以下是我自己经常用的日志路径,你可以直接收藏:

日志文件对应内容适用场景
/var/log/messages系统级通用日志(RedHat/CentOS 系)系统异常、服务崩溃的兜底入口
/var/log/syslog系统级通用日志(Debian/Ubuntu 系)同上,各发行版命名不同
/var/log/secure安全认证日志(RedHat/CentOS 系)登录成败、sudo 提权记录
/var/log/auth.log安全认证日志(Debian/Ubuntu 系)同上
/var/log/dmesg内核环形缓冲区日志硬件故障、驱动加载、OOM
/var/log/boot.log系统启动日志开机过程卡住、服务启动失败
/var/log/cron计划任务执行日志cron 任务不执行时排查
/var/log/nginx/access.logNginx 访问日志Web 访问审计、CC 攻击研判
/var/log/nginx/error.logNginx 错误日志502、504、SSL 握手失败排查
/var/log/mysql/mysql.logMySQL 通用日志数据库请求审计

不同的发行版路径略有差异,比如 Ubuntu 上没有/var/log/secure,而是/var/log/auth.log。这个看起来是小问题,但很多新人换发行版后排障就卡在这一步。

1.3 journald 和 rsyslog 是两套并行体系,必须分清

这是大多数人一开始最容易晕的地方。systemd-journald 负责采集,rsyslog 负责采集加转发归档,二者其实是并列的。现在的发行版里,rsyslog 收集到的许多内容就是通过 socket 从 journald 里读过来的,然后按配置写入/var/log/目录下的文件。所以你用journalctl查到的内容,和tail /var/log/messages查到的内容,大部分是重合的,但journald 会更全,因为它还收集了 stdout、stderr 以及内核对/dev/kmsg的写入。

我建议你在排查时先journalctl,因为它能看到服务进程直接打到标准输出和标准错误上的内容,这个 rsyslog 默认是不会落盘的。等需要做长期归档、集中转发时,再依赖 rsyslog 的规则链。

2. 故障排查:日志不是翻出来的,是顺着线索找出来的

很多朋友问我:为什么我出了问题,翻日志也找不到原因?其实不是日志没记,是你没按线索去翻。日志排查讲究一个顺序和链路。

2.1 我排障时遵循的三条主线

我把排障场景拆成三条主线,每条主线对应不同的日志源和关键词:

  • 内核与硬件层:出现重启、死机、性能骤降、磁盘异常,先看/var/log/dmesgjournalctl -k,关键词重点留意errorfailpanicoomI/O error
  • 系统服务层:某个系统服务(sshd、crond、NetworkManager)状态异常,直接用systemctl status 服务名journalctl -u 服务名,这比去/var/log/messages里瞎翻快得多。
  • 应用与业务层:Nginx、MySQL、Redis 这类应用,它们的日志格式五花八门,去各自的日志目录找错误级别以上的输出,通常能直接看到报错行。

不分层排查,你就容易陷入在 messages 里 grep 一晚上、最后发现是 Nginx 配置写错了的尴尬。

2.2 实战案例:一次半夜 OOM,从 dmesg 里现出原形

有一回客户反馈业务集群里某个节点突然无响应,重启后短暂恢复又挂。监控面板显示 CPU、内存都被拉满,但主业务进程的日志里没有任何异常输出。

我登录机器后先跑了dmesg -T,一眼看到这段:

[Thu Apr 11 03:12:47 2024] Out of memory: Killed process 2314 (java) total-vm:8596 564kB, anon-rss:2635124kB, file-rss:0kB, shmem-rss:0kB, UID:0 pgtables:4628k B oom_score_adj: 0 [Thu Apr 11 03:12:47 2024] oom_reaper: reaped process 2314 (java)

OOM,又是 OOM。Java 进程被内核 OOM Killer 直接杀了。这时再去看业务日志,已经来不及了,进程都死了还写什么日志。这就是我强调一定要先查内核日志的原因——进程被强制杀掉时的“遗言”,只有dmesg里记录得最清楚。

找到 OOM 之后,我继续看是哪个进程吃掉了内存,用top按内存排序,同时配合journalctl --since "1 hour ago" | grep -i "memory"追查是否有进程在持续膨胀。最后定位到一个连接数异常增长的 PHP-FPM 池,把pm.max_children调小、加上进程重启策略,问题才算彻底结束。

2.3 服务起不来,别只盯着 systemctl status

systemctl status输出的那几行信息确实直观,但它通常只显示最近几条日志,很容易误导人。比如 sshd 启动失败时,status 显示failed,但也可能只给出“Permission denied”这种模糊信息,真正的根因还在更早的日志里。

我的习惯是三步走:

systemctl status sshd journalctl -u sshd --since today journalctl -u sshd -p err

第一个命令看状态,第二个命令看完整日志流,第三个命令只捞错误级别以上的记录。很多新人看完第一个就直接在网上搜“sshd failed”,怎么搜也搜不到对应答案,其实根因很可能只是/etc/ssh/sshd_config里一个非法配置项,错误日志在第二、三步里写得清清楚楚。

同理,排 Nginx 的 502 时,我从来不去 Nginx 的 access log 里找答案,因为 502 不是 Nginx 自己产生的,它只是给客户端返回了一个上游错误。这时候必须去看后端的应用日志、PHP-FPM 日志,甚至是 MySQL 的慢查询日志,才能真正定位。

2.4 journalctl 的高频用法,我都给你盘出来

journalctl参数很多,我这里只列我真正常用的组合:

# 查看系统启动后的全部日志(相当于把 messages 从头看一遍) journalctl -b # 查看上一次启动的日志,对比崩溃前后的状态 journalctl -b -1 # 查看最近 30 分钟的日志 journalctl --since "30 min ago" # 按优先级过滤,比较常用的是 err 和 warning journalctl -p err --since "1 hour ago" journalctl -p warning -b # 跟踪某个 unit 的实时输出,相当于 nginx error.log 的 tail -f journalctl -u nginx.service -f # 看内核日志,等价于 dmesg 的更多格式版本 journalctl -k # 按进程过滤,比如盯紧某个 PID 的所有输出 journalctl _PID=12345

很多人不知道journalctl -b后面可以跟负数,这个在排查“重启前发生了什么”时非常有用。进程崩溃往往在重启前瞬间,系统重启后你再journalctl -b看的是当前启动周期,等于把案发现场丢了。

2.5 日志时间线的坑:时区不一致会误判

这算是我踩得最深的一个坑。默认情况下,journald 会用系统本地时区记录时间,而 rsyslog 写文件时有一套自己的时间格式,如果系统时区改过,甚至/var/log/messages里的时间和dmesg -T显示的时间对不上。排查时如果把时间线拉错了,很容易得出完全错误的结论。

建议在排障开始前先确认三处时间是否一致:

date timedatectl dmidecode -s bios-release # 顺带看看硬件时间

如果发现时间不同步,先timedatectl set-local-rtc 0把硬件时钟改成 UTC,再用chronyc makestep校准系统时钟,不然所有日志时间线的关联都会失真。

3. 安全审计:从认证日志里读出攻击者的脚印

安全审计和故障排查看日志的角度完全不一样。故障排查是“我的服务为什么挂了”,安全审计是“系统里有没有不该发生的事”。Logrotate 里的轮转文件、auth 日志里的异常登录、sudo 记录里的越权行为,都是重点盯防目标。

3.1 认证日志里必须认识的几个关键字段

/var/log/secure为例,一条典型的 SSH 登录日志长这样:

Apr 11 03:12:47 web-01 sshd[2314]: Failed password for root from 203.0.113.5 port 45678 ssh2 Apr 11 03:13:01 web-01 sshd[2314]: Accepted publickey for root from 203.0.113.5 port 45678 ssh2

你不需要看懂全部,只需要抓住三个要素:时间、来源 IP、操作结果Accepted代表认证成功,Failed代表认证失败,Invalid user代表尝试登录一个不存在的账户,Connection closed by authenticating user往往代表登录成功了但在认证前被掐断,也可能是试探行为。

我在做安全基线检查时,第一步一定是统计当天Failed password的 TOP 10 来源 IP:

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

如果同一 IP 来源的失败次数超过 50 次,基本可以判定为暴力破解扫描,接下来就是封 IP、检查有无同一来源的成功登录记录。这个检查动作我几乎每周都会做一次,也是客户安全审计最基础的一项。

3.2 暴力破解与撞库的特征识别

仅统计失败次数还不够,攻击者不会只用一台机器。我在实际审计中见过很多更隐蔽的尝试:多 IP 轮换端口扫描式登录、每个 IP 只试两三次、用正常用户名配合大量密码词表。这时候如果还只看单一来源 IP,就很容易漏掉。

我的办法是把“谁在什么时间用了什么用户名从哪些 IP 登录”做成关联分析。有 SIEM 平台的直接做关联规则,没有的话也可以用一条命令粗筛:

journalctl _COMM=sshd --since "1 hour ago" | grep "Failed password" | sed -E 's/.*sshd\[([0-9]+)\]: (Failed password for) (invalid user )?([^ ]+) from ([0-9.]+).*/\4 \5/' | sort | uniq -c | sort -nr | head -20

重点关注的模式有两个:

  • 同一个用户短时间内从多个不相关 IP 出现Failed password,这基本可以断定是横向移动后批量尝试。
  • 某个用户先是Failed password,后来Accepted,说明你可能已经被爆破成功,必须立刻排查该用户的登录来源、命令历史、有无反弹 Shell、有无异常进程。

尤其要注意Accepted publickey,因为很多攻击者在拿到一台机器后会用ssh-keygen生成自己的密钥,然后写入authorized_keys,之后就可以绕过密码静默登录。我每次做安全审计,第一件事就是检查所有用户的~/.ssh/authorized_keys文件有没有异常条目。

3.3 sudo 记录与提权痕迹,别只看登录日志

登录日志只能看到“谁进来了”,看不到“进来之后干了什么”。想做完整的权限审计,sudo日志必须看。

在 Debian/Ubuntu 系默认的认证日志里,sudo 的执行记录也会写进/var/log/auth.log;RedHat 系则在/var/log/secure里。关键字是COMMAND=

Apr 11 03:20:11 web-01 sudo: admin : TTY=pts/0 ; PWD=/home/admin ; USER=root ; COMMAND=/bin/vi /etc/passwd

这条日志意味着 admin 用户通过 sudo 以 root 身份编辑了/etc/passwd。凡是出现/bin/su/etc/sudoers/etc/shadow/etc/ssh/sshd_config/usr/bin/passwd这类路径的 sudo 命令,都要当成高危动作看待。

除了 sudo 本身的记录,journalctl _COMM=sudo也可以作为补充。有时候系统里装了 sudo 的审计补丁,日志会写到自定义文件里,这时再用journalctl _COMM=sudo去查,能拿到更全面的命令记录。

3.4 auditd:系统自带的行为审计利器

说实话,我最早接触日志偏故障排查,对安全审计没什么概念,直到遇到一次“不知道谁把文件改了”的投诉。排查时发现 SSH 登录日志只有一条正常登录,但/etc/passwd莫名多了一个 UID 0 的账户。后来我用auditd复查,一查一个准。

auditd是 Linux 内核层面的审计框架,能记录到用户空间的行为对应到哪个进程、哪个用户、哪个时间。它和普通日志最大的区别是:普通日志是应用程序自愿写的,auditd 是内核强制记录的

以下是我实际项目里用过的一段最小规则:

auditctl -w /etc/passwd -p wa -k passwd-watch auditctl -w /etc/shadow -p wa -k shadow-watch auditctl -w /etc/sudoers -p wa -k sudoers-watch auditctl -a always,exit -F arch=b64 -S execve -k command-exec

第一条规则监控/etc/passwd的写入和属性变化,第二条监控 Shadow 密码文件,第三条监控 sudo 配置,第四条则记录所有命令执行(-k command-exec是自定义的标记)。审计事件会写到/var/log/audit/audit.log,我需要回看某一次命令执行时,直接按这个时间关键词过滤:

ausearch -k command-exec --start today

设定-w时要评估性能开销,尤其是-S execve这种全局命令审计,在高频生产环境下会产生海量日志。我的经验是先在一台机器上试运行一个周期,观察落盘速率,再决定要不要推广。

4. 渗透复盘视角:攻击者与防守者眼中的同一份日志

渗透测试复盘其实可以从两个完全不同的角度去看同一份日志:攻击者看日志是为了“隐身”,防守方看日志是为了“还原”。这两个视角一旦拉齐,就能把防御策略做到位。

说明:以下内容仅为安全防护与授权范围内的渗透测试复盘思路,所谓“攻击者视角”是为了理解对抗思路,所有操作均应在合法授权和合规测试场景下进行,请勿用于未经授权的系统。

4.1 攻击者进入后为什么急着碰日志,通常碰哪些

很多攻击者在拿到一台机器权限之后,第一件事不是翻业务数据,而是清理现场。原因很简单——日志暴露了他进来的路径、用了什么账户、执行了什么命令、目标服务器是什么版本,都写在日志里。

攻击者最常碰的目标,基本就是:

  • /var/log/auth.log/var/log/secure,因为他登录的路径在这里留了痕迹。
  • /var/log/wtmp/var/log/btmp/var/log/utmp,这里记录着登录和登出会话。
  • 当前 shell 的history文件(~/.bash_history),这里记录着他敲过的每一条命令。
  • 如果他有 root 权限,甚至可能直接用shred -z覆写日志文件,配合日志轮转把痕迹冲掉。

更隐蔽的做法是只删除自己会话时间窗口内的日志行,保留其它部分,让日志看起来依然“正常”。这也是为什么防守方要做日志异地实时转发,不能让日志只在被入侵机器本地留一份。

4.2 防守方如何重建攻击链路:时间线拉齐 + 跨源比对

我在一次合法授权测试中的复盘是这样做的:拿到一台被控机器后,先把本地的auth.logdmesgjournalctl全部按时间排序,建立一条以秒为单位的攻击时间线。然后从/var/log/wtmp里拉出所有登录会话,找出攻击者进入了哪些用户、在哪些时间段在线。

接着做跨源比对:Look 一下在那段时间里auth.log里的登录事件,同时从~/.bash_history文件里还原出该用户在 shell 里执行的命令。再把该时间段内落地的文件,比如/tmp下的脚本、/root/.ssh/authorized_keys的新增条目,和 bash history 里的操作一一对应起来。一套完整的攻击链路,基本就能还原个七八成。

这里有个非常关键的点:日志本身也可以被改。如果你在一台被控机器上做复盘,它给出的线索只能作为参考,不能当作绝对证据。真正能定论的是异地保存的日志,所以在企业安全建设中,把日志实时转发到独立的日志平台是底线要求,而不是可选项。

4.3 本地日志被清理后,还能从哪里找线索

如果攻击者清理得很彻底,auth.log里几乎一片空白,这时候别急着放弃,系统里还有几个“不太好清干净”的地方:

  • 内核日志dmesg/var/log/kern.log,攻击者加载 LKM Rootkit 时,内核日志里可能出现异常模块加载记录。
  • 进程时间线/proc目录残留,如果进程还在运行,可以直接从/proc/<pid>/cmdline拿到完整启动命令。
  • 临时文件落盘:shell reverse shell 通常会写入/tmp/dev/shm,这些目录下的小文件别看不上眼,很多时候就是攻击工具的载体。
  • 系统时间线find / -newer /etc/hostname可以列出特定时间后被修改过的文件,配合日志窗口,能快速找到被修改的可疑文件。

另外值得一提的还有PS1或者alias里被注入的恶意命令,它们不会出现在 bash history 里,但会躲在内核日志、进程列表和文件时间线中。这也是为什么复盘时不只看一种日志,而是把所有线索交叉在一起判断。

5. 日志持久化与实时集中收集:好几个坑我已经替你踩过了

最后这部分看着不像日志分析,但恰恰是真正影响“关键时刻能不能查到日志”的幕后功臣。没有持久化和集中收集,前面所有方法论都是空中楼阁。

5.1 journald 默认不写磁盘,这是一个大坑

journald默认把日志写到内存临时文件/run/log/journal/,机器一重启全丢。你没看错,就是默认全丢,除非你专门开启了持久化。

这个坑我印象太深了——有次排查一个内存奔溃的问题,好不容易拿到现场,可一重启,systemd 的所有日志都被清空,等于白跑一趟。从那以后,我每装一台 Linux 机器第一件事就是执行这几条命令:

mkdir -p /var/log/journal systemd-tmpfiles --create --prefix /var/log/journal systemctl restart systemd-journald

开启持久化之后,journald 会把日志写入/var/log/journal/,就再也不会因为重启而丢了。

5.2 journald 的存储上限配置

持久化开启后还有一个隐患:journald 是无冕之王,它会把所有内容都攒下来,不管空间够不够。如果不限制上限,时间长了可能涨到大几十 GB,反过来把系统盘给吃满,那就得不偿失了。

我一般会在/etc/systemd/journald.conf里这样调:

SystemMaxUse=500M SystemMaxFileSize=100M MaxRetentionSec=2weeks

SystemMaxUse=500M是 journal 总容量上限,超过这个值后 journald 会按时间顺序清理旧日志;SystemMaxFileSize=100M是单个 journal 文件大小;MaxRetentionSec=2weeks保证日志最多保留两周,配合异地转发,本地存多久都问题不大。

改完配置文件记得重启服务:

systemctl restart systemd-journald

5.3 rsyslog 的文件轮转与集中转发

journald 解决的是采集和读取,rsyslog 解决的是落盘与转发。两者经常要配合着用。

/var/log/下的文件,rsyslog 默认已经配了 logrotate 的每日轮转,但你最好先看一下/etc/logrotate.d/下的配置,确认:

  • 轮转周期是 day 还是 size,比如 sshd 日志可以配成按大小轮转,防止超大文件。
  • 保留周期是否满足审计要求,比如安全审计通常要求保留 180 天以上。
  • 轮转后是否执行了reload rsyslog,不然 rsyslog 继续往已轮转的文件里写,可能报文件句柄错误。

日志的集中转发,最简单的方式是 rsyslog 的远程日志:

# 在 /etc/rsyslog.conf 或 /etc/rsyslog.d/remote.conf 中配置 *.* @log-collector.example.com:514

这条配置把本机所有 syslog 消息转发到log-collector的 UDP 514 端口。UDP 适合日志量不大、允许丢失的场景;生产环境建议用 TCP,加@@log-collector.example.com:514,可靠性更高。现在企业里更常见的是用 Loki、ELK 一类的日志平台做集中存储与检索,相关配置网上很多,我这里只说一句——不管用什么平台,一定要把转发出口做在系统层,而不是只靠业务进程自己上报,否则一旦应用进程被攻击者接管,它可以选择不报或者报假数据。

5.4 定时任务日志里的低频陷阱

最后提一个 cron 日志的坑。很多人觉得 cron 日志没什么用,但其实/var/log/cron里记录着所有计划任务的执行历史和结果。如果某个定时备份脚本凌晨每天执行,某一天突然没有日志输出,那通常意味着任务没被触发,或者脚本第一行就报错了。

journalctl -u crond --since today也能看到 crond 服务的运行状态,我建议把备份类脚本的日志独立输出到自定义文件,并在脚本里加上失败退出码判断,这样排障时就不用大海捞针。

我在实际项目中最常做的一件事,就是把每分钟的 cron 执行记录和 auth 日志、应用日志做时间轴比对,这种低频痕迹往往能帮你把“看似正常”的故障和真实的安全事件联系在一起。

Linux 日志这东西,说复杂可以很复杂,说简单其实就一条逻辑:先知道日志在哪,再知道怎么看,最后理解每个字段背后的含义。把故障排查的三条主线和安全审计的四个抓手记牢,再配上 journald 的持久化和集中转发,绝大部分问题都能在半小时内定位到根因。我现在每接手一台新机器,都会先把日志落盘、转发、轮转这三件事检查一遍,别等真出事了才想起来,到时候哭都来不及。

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

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

立即咨询