Debian服务器长期暴露在公网环境,安全扫描不能只靠人工想起来才跑一次。定时执行安全扫描的核心价值在于把漏洞发现的时间窗口压缩到最小,同时让扫描结果可追溯、可对比。要实现这一点,不能只装一个工具然后随便丢个cron任务,需要从扫描工具选型、定时策略、报告处理和自动响应四个层面做完整设计。

先明确一个基本判断:Debian官方仓库里自带的扫描工具足够覆盖绝大多数场景,不需要引入第三方源或编译安装。lynis、debsecan、rkhunter、chkrootkit这四个工具组合起来,能从系统配置审计、已知CVE比对、Rootkit检测三个维度形成互补。其中lynis负责系统加固层面的检查,debsecan直接对接Debian安全公告,rkhunter和chkrootkit侧重入侵痕迹发现。四者定位不同,定时任务里应该全部纳入。

安装核心扫描工具并做基础配置

在Debian 11/12上执行以下命令安装全部工具:

apt update && apt install -y lynis debsecan rkhunter chkrootkit mailutils

安装完成后先手动跑一遍lynis,让它生成初始基线报告。执行

lynis audit system --quick
,报告会输出到/var/log/lynis.log。第一次跑会暴露很多配置项,其中一部分是Debian默认策略导致的误报,需要人工过滤。建议把第一次报告完整看一遍,确认哪些是真实风险,哪些可以忽略。后续定时扫描的对比才有意义。

debsecan需要先配置数据源。编辑/etc/default/debsecan,确认里面的RELEASE字段对应你的Debian版本代号,比如bullseye或bookworm。然后执行

debsecan --format detail
测试能否正常拉取安全公告数据。如果输出为空或者报错,检查网络和/etc/apt/sources.list里的deb-src源是否启用,debsecan依赖源码包索引来匹配CVE。

rkhunter第一次运行前必须更新数据库并做属性初始化,否则后续扫描会报大量文件变更警告。执行:

rkhunter --update
rkhunter --propupd

这两步很关键,--propupd会把当前系统关键文件的哈希值记录下来作为可信基线。之后每次扫描都会和这个基线比对,发现文件被篡改就会报警。

设计定时任务的执行顺序和频率

四个工具的执行频率不应该一刀切。lynis的系统审计比较耗时,每天跑一次没必要,每周一次足够。debsecan查CVE依赖安全公告更新,Debian安全团队通常每天都有更新,所以每天跑一次合理。rkhunter和chkrootkit的Rootkit检测属于入侵检测范畴,建议每天凌晨执行,并且时间上要错开,避免同时占用IO资源。

具体cron配置参考如下,编辑/etc/crontab或者用crontab -e:

# 每天凌晨2点执行debsecan CVE比对
0 2 * * * root /usr/bin/debsecan --format detail > /var/log/debsecan-daily.log 2>&1

# 每天凌晨3点执行rkhunter检测
0 3 * * * root /usr/bin/rkhunter --check --skip-keypress --report-warnings-only > /var/log/rkhunter-daily.log 2>&1

# 每天凌晨4点执行chkrootkit检测
0 4 * * * root /usr/sbin/chkrootkit > /var/log/chkrootkit-daily.log 2>&1

# 每周日凌晨5点执行lynis完整审计
0 5 * * 0 root /usr/sbin/lynis audit system --quiet > /var/log/lynis-weekly.log 2>&1

注意rkhunter必须加--skip-keypress参数,否则在cron环境下会因为等待键盘输入而卡住。--report-warnings-only可以让日志只记录警告项,减少噪音。chkrootkit直接输出到日志即可,它本身没有复杂的交互逻辑。

扫描结果过滤与告警机制

定时扫描最大的问题不是扫不出来问题,而是日志太多没人看。如果每天生成的日志都堆在/var/log里,过两周你就不会再打开它们了。必须设计一个过滤层,只把真正需要人工介入的内容推送出来。

对于debsecan,它的输出格式里包含CVE编号、严重程度和包名。可以写一个简单的shell脚本,只提取高危漏洞:

#!/bin/bash
LOG=/var/log/debsecan-daily.log
if grep -q "remotely exploitable\|high urgency" "$LOG"; then
    grep -B2 -A2 "remotely exploitable\|high urgency" "$LOG" | mail -s "Debian高危漏洞告警" admin@example.com
fi

把这个脚本放在debsecan执行之后运行,cron里追加一行:

10 2 * * * root /usr/local/bin/debsecan-alert.sh

rkhunter的告警过滤更直接,它输出的Warning行就是需要关注的。用grep提取Warning并发送邮件:

#!/bin/bash
LOG=/var/log/rkhunter-daily.log
if grep -q "Warning" "$LOG"; then
    grep "Warning" "$LOG" | mail -s "rkhunter安全告警" admin@example.com
fi

lynis的周报处理方式不同。它的输出很长,建议用lynis自带的report格式,然后提取suggestion和warning部分。lynis执行时加--auditor参数可以指定审计员名称,报告会生成在/var/log/lynis-report.dat。用脚本解析这个dat文件,提取warning和suggestion条目:

#!/bin/bash
REPORT=/var/log/lynis-report.dat
if [ -f "$REPORT" ]; then
    grep -E "warning|suggestion" "$REPORT" | mail -s "lynis周度审计摘要" admin@example.com
fi
日志轮转与历史留存

扫描日志不能无限增长,必须配置logrotate。在/etc/logrotate.d/下创建一个安全扫描专用的配置文件:

/var/log/debsecan-daily.log /var/log/rkhunter-daily.log /var/log/chkrootkit-daily.log /var/log/lynis-weekly.log {
    weekly
    rotate 8
    compress
    missingok
    notifempty
    create 640 root adm
}

rotate 8意味着保留最近8周的日志,足够做趋势对比。如果磁盘空间紧张可以改成rotate 4。压缩后的日志占用很小,但需要回溯时还能解压查看。

自动修复的边界与风险控制

很多人想实现扫描发现漏洞后自动升级修复,这个想法在Debian服务器上要非常谨慎。自动执行apt upgrade可能引入依赖变更、服务重启甚至配置兼容问题。对于生产环境,自动修复只应该覆盖一个场景:debsecan报告的高危CVE且该CVE有官方安全更新。

可以写一个受控的自动修复脚本,只升级debsecan报告涉及的包,而不是全量upgrade:

#!/bin/bash
# 提取debsecan报告中需要升级的包名
PACKAGES=$(debsecan --format packages 2>/dev/null | sort -u)
if [ -n "$PACKAGES" ]; then
    apt-get update
    apt-get install -y --only-upgrade $PACKAGES
fi

这个脚本的风险在于debsecan输出的包名可能包含内核包,升级内核需要重启才能生效,而且内核升级失败可能导致系统无法启动。建议在内核包上做排除,或者干脆把自动修复限制在非内核包。更稳妥的做法是只自动修复标记为“remotely exploitable”的漏洞对应包,这类漏洞通常是最紧迫的。

rkhunter和chkrootkit发现的异常绝对不能自动处理。Rootkit告警可能是误报,也可能是真实入侵。自动删除文件或恢复哈希基线会破坏取证现场。正确做法是告警后人工登录检查,确认是误报再执行

rkhunter --propupd
更新基线,确认是入侵则立即下线排查。

扫描任务本身的可靠性保障

定时任务本身也可能失败。cron默认会把执行错误发到root邮箱,但如果服务器没配置邮件转发,这些错误就石沉大海。建议在cron里加一个简单的执行标记,每次扫描完成后写入时间戳,另一个监控脚本检查时间戳是否更新:

# 在扫描任务末尾追加时间戳写入
0 2 * * * root /usr/bin/debsecan --format detail > /var/log/debsecan-daily.log 2>&1 && date +\%s > /var/run/debsecan.last

然后每天中午检查一次时间戳,如果超过24小时没更新就说明凌晨的任务失败了:

#!/bin/bash
LAST=$(cat /var/run/debsecan.last 2>/dev/null)
NOW=$(date +%s)
if [ -z "$LAST" ] || [ $((NOW - LAST)) -gt 86400 ]; then
    echo "debsecan扫描任务未正常执行" | mail -s "扫描任务异常" admin@example.com
fi

这个机制能保证扫描任务本身不会静默失效。很多服务器被入侵后,攻击者第一件事就是删除或篡改cron任务,时间戳监控能发现这种异常。

Debian特有注意事项

Debian的稳定版策略决定了它的软件包版本更新较慢,安全修复通过backports和security仓库推送。务必确认/etc/apt/sources.list里包含security.debian.org的源,否则debsecan拉取到的CVE信息无法对应到可用的修复包。执行

apt-cache policy | grep -A2 "security.debian.org"
检查安全源是否生效。

另外Debian的默认内核参数和文件权限相对保守,lynis会报告大量“建议加固”项,其中很多在Debian默认配置下已经是合理状态。不要盲目按照lynis的suggestion逐条修改,尤其是涉及PAM、sysctl和SSH配置的项。每改一项都要评估对现有业务的影响。lynis的价值在于提供检查清单,而不是替代人工判断。

最后强调一点:定时安全扫描是检测手段,不是防御手段。它不能阻止攻击发生,只能让你更快知道攻击已经发生或者系统存在可被利用的漏洞。扫描结果必须有人看、有人处理,否则整套机制就是自我安慰。把告警邮件配置到真正会处理的人邮箱里,比任何工具参数调优都重要。