系统服务与进程防护:服务最小化原则、systemd安全配置、进程监控与异常检测

系统跑起来之后,第一件事是什么?我个人习惯是——先砍服务。你想想看,一个刚装好的Linux系统,默认开了多少你根本用不上的东西?CUPS打印服务、Avahi零配置网络、蓝牙栈……这些在服务器上就是活生生的攻击面。

我在项目中遇到过好几次,客户说“我们被入侵了”,结果一查,攻击者就是从某个没人记得的默认服务进来的。嗯,这章我们就来聊聊怎么把系统服务管好,从源头减少风险。

服务最小化原则:能不开就不开

说白了,服务最小化就是一句话:只装你需要的,只开你用的。别觉得多一个服务无所谓,每一个监听端口都是一扇可能被撬开的门。

核心思路:攻击面 = 运行中的服务数量 × 每个服务的漏洞概率。减少服务,就是直接降低风险。

具体怎么做?我一般分三步走:

  1. 安装时选最小化——用发行版的“最小安装”选项,别图省事装完整版。
  2. 安装后审计——用 systemctl list-units --type=service --state=running 看看当前跑了哪些服务。
  3. 逐个确认——每个服务问自己:这台机器真的需要它吗?

我曾经帮一个团队做安全审计,发现他们的数据库服务器上居然跑着Apache和Postfix。问了一圈没人知道为什么。停掉之后,CPU负载降了30%,攻击面也小了一大截。

服务类型 常见默认服务 建议操作
打印服务 cups.service 禁用(服务器)
蓝牙 bluetooth.service 禁用
零配置网络 avahi-daemon.service 禁用
邮件传输 postfix.service / sendmail.service 如不需要则禁用
NFS nfs-server.service 按需启用

小技巧:用 systemctl list-unit-files --type=service | grep enabled 查看所有开机自启的服务。你会发现不少惊喜(或者说惊吓)。

systemd安全配置:别只用默认值

systemd现在是主流Linux的初始化系统,功能很强。但很多人只是用它来 start 和 stop,完全没用到它的安全特性。其实,每个service文件里都能加不少安全选项。

我建议你养成习惯,写service文件时至少加上这几项:

[Service]
# 限制文件系统访问
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/myapp /var/log/myapp

# 限制网络访问
PrivateNetwork=false   # 如果不需要网络,设为true

# 限制系统调用
SystemCallFilter=@system-service
SystemCallArchitectures=native

# 限制能力
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE

# 其他隔离
NoNewPrivileges=true
PrivateTmp=true
ProtectKernelModules=true
ProtectKernelTunables=true

这些选项能做什么?我简单解释一下:

  • ProtectSystem=strict——让服务只能写你指定的目录,其他系统目录只读。
  • NoNewPrivileges=true——防止服务通过 setuid 等方式提权。
  • PrivateTmp=true——每个服务有自己的临时目录,避免/tmp下的竞争条件攻击。

注意:别一股脑全加上。有些选项会破坏服务的正常运行。比如数据库需要写数据目录,你设了 ProtectSystem=strict 又不加 ReadWritePaths,它就跑不起来了。我建议先在测试环境验证。

我记得有一次,一个同事的Web应用被注入了webshell,攻击者想通过它执行系统命令。但因为service文件里配了 SystemCallFilter=@system-service 和 NoNewPrivileges=true,攻击者根本调不了 execve 和 fork,直接卡死。这就是配置的价值。

进程监控与异常检测:看得见才防得住

配置再好,也挡不住所有攻击。你还需要一双眼睛,时刻盯着系统里的进程。我个人习惯用三层监控:

  1. 系统层——用 ps、top、htop 手动检查。
  2. 工具层——用 auditd、sysdig 记录进程行为。
  3. 自动化层——写脚本或配置告警,发现异常自动通知。

手动检查:快速定位异常

先看几个常用命令:

# 查看所有进程,重点关注资源消耗异常的
ps aux --sort=-%cpu | head -20

# 查看网络连接,找可疑的监听端口
ss -tlnp

# 查看隐藏进程(利用 /proc 比对)
ps aux | awk '{print $2}' | sort -n > /tmp/ps_pids.txt
ls /proc | grep -E '^[0-9]+$' | sort -n > /tmp/proc_pids.txt
diff /tmp/ps_pids.txt /tmp/proc_pids.txt

最后那个diff命令,是我自己常用的。有些rootkit会隐藏进程,ps 看不到但 /proc 里还有痕迹。一对比,猫腻就出来了。

auditd:记录一切

auditd是Linux自带的审计系统。配置好之后,它能记录谁在什么时候启动了哪个进程。

# 安装
apt install auditd

# 添加规则:监控 /usr/bin 下的执行
auditctl -w /usr/bin -p x -k binary-execution

# 查看日志
ausearch -k binary-execution --start today

我在项目中遇到过一件事:某台服务器CPU突然飙高,但 top 里看不到异常进程。用 ausearch 一查,发现凌晨3点有人通过一个Web漏洞上传了挖矿程序,进程名伪装成 [kworker]。auditd记录下了它的完整路径和启动方式,直接定位了问题。

自动化检测:写个简单的监控脚本

手动检查不能24小时盯着。我一般会写个简单的脚本,配合cron或systemd timer跑:

#!/bin/bash
# 进程异常检测脚本

# 白名单:已知的正常进程名
WHITELIST="sshd|nginx|mysqld|systemd|bash|cron|rsyslogd"

# 获取所有进程名
PROCESSES=$(ps -eo comm= | sort -u)

# 检查是否有不在白名单的进程
echo "$PROCESSES" | while read proc; do
    if ! echo "$proc" | grep -qE "$WHITELIST"; then
        echo "[WARNING] 未知进程: $proc (PID: $(pgrep -x $proc))"
    fi
done

# 检查CPU占用过高的进程
ps aux --sort=-%cpu | awk 'NR>1 && $3>50 {print "[ALERT] CPU过高: " $11 " (" $3 "%)"}'

当然,这只是个雏形。生产环境里,我建议用 osquery 或 Wazuh 这类成熟工具。但原理是一样的——知道什么是正常,才能发现什么是异常。

经验之谈:建立进程基线很重要。新装系统后,先记录一份“干净”的进程列表。以后对比,一眼就能看出多了什么。我习惯把基线存在版本控制里,每次变更都更新。

本章知识体系

下面这张图,把服务与进程防护的核心逻辑串起来了:

系统服务与进程防护知识体系 服务最小化原则 systemd安全配置 进程监控与异常检测 具体措施 • 最小化安装 • 审计运行服务 • 逐个确认必要性 关键配置项 • ProtectSystem / ProtectHome • NoNewPrivileges / PrivateTmp • SystemCallFilter / CapabilityBoundingSet 监控手段 • ps / ss 手动检查 • auditd 审计记录 • 自动化检测脚本 减少攻击面 · 限制权限 · 及时发现异常 核心逻辑 服务最小化 → 减少入口 systemd安全配置 → 加固每个服务 进程监控 → 发现突破后的行为

这三层是递进关系。先砍掉不需要的服务,再把剩下的服务用systemd锁好,最后盯着进程看有没有人搞小动作。少一环都不行。

最后提醒一句:别以为配完就万事大吉了。系统是动态的,今天装个新软件,明天更新个补丁,都可能引入新服务。我建议每个月至少做一次服务审计,把“最小化”当成一个持续的过程,而不是一次性任务。