系统服务与进程防护:服务最小化原则、systemd安全配置、进程监控与异常检测
系统跑起来之后,第一件事是什么?我个人习惯是——先砍服务。你想想看,一个刚装好的Linux系统,默认开了多少你根本用不上的东西?CUPS打印服务、Avahi零配置网络、蓝牙栈……这些在服务器上就是活生生的攻击面。
我在项目中遇到过好几次,客户说“我们被入侵了”,结果一查,攻击者就是从某个没人记得的默认服务进来的。嗯,这章我们就来聊聊怎么把系统服务管好,从源头减少风险。
服务最小化原则:能不开就不开
说白了,服务最小化就是一句话:只装你需要的,只开你用的。别觉得多一个服务无所谓,每一个监听端口都是一扇可能被撬开的门。
核心思路:攻击面 = 运行中的服务数量 × 每个服务的漏洞概率。减少服务,就是直接降低风险。
具体怎么做?我一般分三步走:
- 安装时选最小化——用发行版的“最小安装”选项,别图省事装完整版。
- 安装后审计——用
systemctl list-units --type=service --state=running看看当前跑了哪些服务。 - 逐个确认——每个服务问自己:这台机器真的需要它吗?
我曾经帮一个团队做安全审计,发现他们的数据库服务器上居然跑着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,直接卡死。这就是配置的价值。
进程监控与异常检测:看得见才防得住
配置再好,也挡不住所有攻击。你还需要一双眼睛,时刻盯着系统里的进程。我个人习惯用三层监控:
- 系统层——用
ps、top、htop手动检查。 - 工具层——用
auditd、sysdig记录进程行为。 - 自动化层——写脚本或配置告警,发现异常自动通知。
手动检查:快速定位异常
先看几个常用命令:
# 查看所有进程,重点关注资源消耗异常的
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锁好,最后盯着进程看有没有人搞小动作。少一环都不行。
最后提醒一句:别以为配完就万事大吉了。系统是动态的,今天装个新软件,明天更新个补丁,都可能引入新服务。我建议每个月至少做一次服务审计,把“最小化”当成一个持续的过程,而不是一次性任务。