CentOS服务器定时安全巡检的核心思路,是把平时需要手动执行的检查命令固化成脚本,再交给crontab定时触发,把结果以日志或邮件形式留存。这样既能避免遗忘,也能在异常发生时第一时间拿到线索。下面直接拆解一套可落地的配置方案,覆盖账号、登录、文件、进程、网络、资源占用和关键服务状态,脚本可以直接复制修改使用。
先明确巡检脚本要检查哪些维度。安全巡检不是跑一个命令就完事,至少要覆盖这几个方面:异常登录和账号变动、敏感文件权限变化、异常进程和网络连接、CPU内存磁盘资源是否异常、关键服务是否存活、日志中是否出现高频攻击特征。把这些检查项写进一个bash脚本,每次执行输出带时间戳的结果,后续排查就有据可查。
创建巡检目录和主脚本文件。建议放在/opt/security_check/下,权限设为700,只允许root读写执行。执行以下命令:
mkdir -p /opt/security_check touch /opt/security_check/security_check.sh chmod 700 /opt/security_check/security_check.sh
接下来编写脚本内容。脚本开头先定义输出文件和邮件接收地址,然后逐项执行检查。输出文件按日期命名,保留最近30天的记录,方便回溯。
#!/bin/bash
# CentOS服务器定时安全巡检脚本
# 建议通过crontab每天凌晨执行
DATE=$(date +%Y%m%d_%H%M%S)
OUTPUT_DIR="/opt/security_check/reports"
OUTPUT_FILE="${OUTPUT_DIR}/security_report_${DATE}.txt"
MAIL_TO="admin@example.com"
HOSTNAME=$(hostname)
mkdir -p ${OUTPUT_DIR}
echo "============================================" > ${OUTPUT_FILE}
echo "服务器安全巡检报告 - ${HOSTNAME}" >> ${OUTPUT_FILE}
echo "巡检时间: $(date '+%Y-%m-%d %H:%M:%S')" >> ${OUTPUT_FILE}
echo "============================================" >> ${OUTPUT_FILE}
echo "" >> ${OUTPUT_FILE}
第一项检查账号与登录安全。查看/etc/passwd中是否有UID为0的非root账号,检查空密码账号,以及最近登录失败的记录。空密码账号是极其危险的存在,必须列为重点。
echo "[1] 账号安全检查" >> ${OUTPUT_FILE}
echo "------------------------------------------" >> ${OUTPUT_FILE}
# 检查UID为0的账号
echo "UID为0的账号:" >> ${OUTPUT_FILE}
awk -F: '($3 == 0) {print $1}' /etc/passwd >> ${OUTPUT_FILE}
# 检查空密码账号
echo "空密码账号:" >> ${OUTPUT_FILE}
awk -F: '($2 == "") {print $1}' /etc/shadow >> ${OUTPUT_FILE}
# 检查可登录账号列表
echo "可登录账号:" >> ${OUTPUT_FILE}
grep -v '/sbin/nologin\|/bin/false' /etc/passwd | cut -d: -f1 >> ${OUTPUT_FILE}
# 最近10条登录失败记录
echo "最近登录失败记录:" >> ${OUTPUT_FILE}
lastb -n 10 2>/dev/null >> ${OUTPUT_FILE}
echo "" >> ${OUTPUT_FILE}
第二项检查敏感文件权限。重点检查/etc/passwd、/etc/shadow、/etc/group、/etc/gshadow、/etc/sudoers这些文件的权限是否被篡改。正常情况下shadow和gshadow权限应为000或400,sudoers应为440。如果权限变宽,说明可能被入侵或误操作。
echo "[2] 敏感文件权限检查" >> ${OUTPUT_FILE}
echo "------------------------------------------" >> ${OUTPUT_FILE}
for file in /etc/passwd /etc/shadow /etc/group /etc/gshadow /etc/sudoers; do
if [ -f "$file" ]; then
perms=$(stat -c "%a %U:%G" $file)
echo "$file 权限: $perms" >> ${OUTPUT_FILE}
fi
done
# 检查全局可写文件
echo "全局可写文件(部分):" >> ${OUTPUT_FILE}
find / -xdev -type f -perm -0002 ! -path "/proc/*" ! -path "/sys/*" ! -path "/dev/*" 2>/dev/null | head -20 >> ${OUTPUT_FILE}
echo "" >> ${OUTPUT_FILE}
第三项检查异常进程和网络连接。通过ps和netstat/ss找出可疑进程、监听端口和外部连接。重点看非标准端口、异常外联IP、以及以root身份运行的陌生进程。CentOS 7及以上用ss命令替代netstat。
echo "[3] 进程与网络连接检查" >> ${OUTPUT_FILE}
echo "------------------------------------------" >> ${OUTPUT_FILE}
# 占用CPU最高的前10个进程
echo "CPU占用TOP10进程:" >> ${OUTPUT_FILE}
ps aux --sort=-%cpu | head -11 >> ${OUTPUT_FILE}
# 监听端口
echo "监听端口:" >> ${OUTPUT_FILE}
ss -tulnp 2>/dev/null >> ${OUTPUT_FILE}
# 已建立的TCP连接
echo "已建立的TCP连接:" >> ${OUTPUT_FILE}
ss -tnp state established 2>/dev/null | head -20 >> ${OUTPUT_FILE}
# root用户运行的进程数量
echo "root用户进程数:" >> ${OUTPUT_FILE}
ps -U root -u root | wc -l >> ${OUTPUT_FILE}
echo "" >> ${OUTPUT_FILE}
第四项检查资源使用情况。磁盘使用率超过80%要告警,内存和swap使用率过高也可能导致服务异常。用df、free命令提取关键数据。
echo "[4] 系统资源检查" >> ${OUTPUT_FILE}
echo "------------------------------------------" >> ${OUTPUT_FILE}
echo "磁盘使用情况:" >> ${OUTPUT_FILE}
df -h >> ${OUTPUT_FILE}
echo "内存使用情况:" >> ${OUTPUT_FILE}
free -h >> ${OUTPUT_FILE}
echo "系统负载:" >> ${OUTPUT_FILE}
uptime >> ${OUTPUT_FILE}
echo "" >> ${OUTPUT_FILE}
第五项检查关键服务状态。根据实际业务调整服务列表,比如sshd、crond、firewalld、nginx、mysql等。用systemctl is-active判断服务是否运行,输出异常项。
echo "[5] 关键服务状态检查" >> ${OUTPUT_FILE}
echo "------------------------------------------" >> ${OUTPUT_FILE}
SERVICES="sshd crond firewalld network"
for svc in ${SERVICES}; do
status=$(systemctl is-active ${svc} 2>/dev/null)
echo "${svc}: ${status}" >> ${OUTPUT_FILE}
done
echo "" >> ${OUTPUT_FILE}
第六项检查日志中的攻击特征。从/var/log/secure中统计SSH暴力破解尝试,查看是否有大量Failed password记录,以及最近成功登录的IP。如果某个IP失败次数异常多,可以在后续脚本中加入自动封禁逻辑。
echo "[6] 日志安全检查" >> ${OUTPUT_FILE}
echo "------------------------------------------" >> ${OUTPUT_FILE}
# SSH登录失败次数统计
echo "SSH登录失败次数TOP10 IP:" >> ${OUTPUT_FILE}
grep "Failed password" /var/log/secure 2>/dev/null | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -10 >> ${OUTPUT_FILE}
# 最近成功登录记录
echo "最近成功登录记录:" >> ${OUTPUT_FILE}
grep "Accepted" /var/log/secure 2>/dev/null | tail -10 >> ${OUTPUT_FILE}
# 检查是否有可疑的提权操作
echo "sudo使用记录:" >> ${OUTPUT_FILE}
grep "sudo" /var/log/secure 2>/dev/null | tail -10 >> ${OUTPUT_FILE}
echo "" >> ${OUTPUT_FILE}
第七项检查计划任务和启动项。很多持久化后门会写入crontab或/etc/rc.local。检查所有用户的crontab文件和系统级cron目录,查看是否有陌生条目。
echo "[7] 计划任务与启动项检查" >> ${OUTPUT_FILE}
echo "------------------------------------------" >> ${OUTPUT_FILE}
echo "系统crontab内容:" >> ${OUTPUT_FILE}
cat /etc/crontab 2>/dev/null >> ${OUTPUT_FILE}
echo "cron目录文件列表:" >> ${OUTPUT_FILE}
ls -la /etc/cron.d/ /etc/cron.daily/ /etc/cron.hourly/ /etc/cron.weekly/ /etc/cron.monthly/ 2>/dev/null >> ${OUTPUT_FILE}
echo "各用户crontab:" >> ${OUTPUT_FILE}
for user in $(cut -f1 -d: /etc/passwd); do
crontab -l -u ${user} 2>/dev/null | grep -v "^#" | grep -v "^$" | while read line; do
echo "${user}: ${line}" >> ${OUTPUT_FILE}
done
done
echo "" >> ${OUTPUT_FILE}
脚本主体写完后,在末尾加上清理逻辑和邮件发送。清理30天前的旧报告,然后把本次报告发送到指定邮箱。邮件发送依赖mailx,需要提前安装配置。
# 清理30天前的旧报告
find ${OUTPUT_DIR} -name "security_report_*.txt" -mtime +30 -delete
# 发送邮件
if command -v mailx &> /dev/null; then
mail -s "【安全巡检】${HOSTNAME} $(date '+%Y-%m-%d')" ${MAIL_TO} < ${OUTPUT_FILE}
fi
echo "巡检完成,报告保存在: ${OUTPUT_FILE}"
把以上所有代码段按顺序合并成一个完整的security_check.sh文件,保存后赋予执行权限。然后手动执行一次,确认没有报错,输出报告内容符合预期。
chmod +x /opt/security_check/security_check.sh /opt/security_check/security_check.sh
手动执行成功后,配置crontab定时任务。编辑crontab:
crontab -e
添加以下行,表示每天凌晨2点执行巡检:
0 2 * * * /opt/security_check/security_check.sh >> /opt/security_check/run.log 2>&1
保存退出后,可以用crontab -l确认任务已添加。如果服务器上邮件服务未配置,也可以把报告输出到指定目录,再通过其他监控系统采集。对于没有mailx的环境,可以安装mailx并配置SMTP,或者改用curl把报告推送到企业微信、钉钉机器人,这样告警时效性更强。
针对CentOS 6和CentOS 7/8的差异,需要注意几个细节。CentOS 6使用service和chkconfig管理服务,脚本中的systemctl命令需要替换为service。ss命令在CentOS 6上可能不存在,需要用netstat -tulnp替代。lastb命令在部分精简系统上可能没有,可以改用grep读取/var/log/btmp。脚本中已经做了2>/dev/null容错处理,但实际部署前最好先确认命令是否存在。
如果希望巡检更智能,可以在脚本中加入阈值判断和自动告警。比如磁盘使用率超过85%时,在报告顶部追加WARNING标记;SSH失败次数超过100次的IP,自动加入hosts.deny或firewalld黑名单。下面给出一个自动封禁SSH暴力破解IP的增强片段,可以插入到日志检查之后:
# 自动封禁SSH暴力破解IP(失败次数超过50次)
BLOCK_THRESHOLD=50
grep "Failed password" /var/log/secure 2>/dev/null | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | while read count ip; do
if [ ${count} -gt ${BLOCK_THRESHOLD} ]; then
if ! firewall-cmd --list-rich-rules 2>/dev/null | grep -q ${ip}; then
firewall-cmd --permanent --add-rich-rule="rule family='ipv4' source address='${ip}' reject" 2>/dev/null
echo "已自动封禁IP: ${ip} (失败${count}次)" >> ${OUTPUT_FILE}
fi
fi
done
firewall-cmd --reload 2>/dev/null
这段逻辑会把暴力破解超过50次的IP永久封禁,前提是firewalld正在运行。如果使用iptables,可以替换成iptables -A INPUT -s IP -j DROP。自动封禁能显著降低SSH被爆破成功的风险,但阈值要设置合理,避免误封正常用户。
关于巡检频率,每天一次是基础要求。对于核心业务服务器,建议增加到每6小时一次,并把报告实时推送到运维群。如果服务器数量多,可以把脚本分发到各节点,报告统一收集到一台日志服务器,再配合简单的Web界面或ELK做集中展示。单机巡检脚本是基础,规模化后需要考虑集中管理和告警去重。
还有一点容易被忽略:巡检脚本本身的安全。脚本中如果包含邮件密码或API密钥,权限必须是700,且不要放在Web可访问目录下。脚本输出的报告包含大量敏感信息,报告目录同样要限制访问。建议把报告目录权限设为700,仅root可读。
最后验证整个流程是否闭环:手动执行脚本能生成报告,crontab定时能触发,邮件或推送能收到,报告内容能覆盖关键安全维度,异常项能及时被发现。这四步都跑通,CentOS服务器的定时安全巡检配置就真正落地了。后续根据业务变化,定期更新检查项和阈值,让巡检脚本持续适配服务器实际状态。
