首页 / 资讯动态 / Ubuntu系统每次重启后的安全状态检查

Ubuntu系统每次重启后的安全状态检查

重启服务器后直接跑业务,是运维中最危险的习惯。Ubuntu系统重启后,防火墙规则可能丢失、敏感服务可能因挂载点未就绪而裸奔、自动更新可能改动了关键配置。你需要一套标准化的检查流程,确保每次重启后系统处于预期的安全状态,而不是凭感觉认为“应该没问题”。

确认防火墙是否真正生效

Ubuntu默认使用ufw作为iptables的前端管理工具。重启后最容易被忽略的问题是ufw服务虽然显示active,但iptables规则表可能为空。直接执行sudo ufw status,如果输出显示Status: inactive,说明防火墙根本没起来。更隐蔽的情况是ufw显示active,但底层规则丢失,这通常发生在使用Docker或其他直接操作iptables的工具之后。验证方法是用sudo iptables -L -n查看当前规则链,确认INPUT链的默认策略是DROP,并且能看到你预设的放行端口。如果默认策略是ACCEPT,你的防火墙形同虚设。

另一个关键点是检查ufw是否被systemd正确管理。执行sudo systemctl is-enabled ufw确认服务已设置为开机自启。有些云厂商的Ubuntu镜像默认禁用ufw,你需要手动执行sudo systemctl enable ufw。同时检查是否存在其他防火墙管理工具冲突,比如firewalld或nftables,它们可能在你不知情的情况下接管了网络过滤。

验证SSH服务的安全配置

重启后SSH服务会重新加载配置文件,但如果你之前手动修改过/etc/ssh/sshd_config,需要确认修改没有被覆盖。重点检查三项:PermitRootLogin是否设为no或prohibit-password,PasswordAuthentication是否已禁用,Port是否已修改为非默认端口。执行sudo sshd -t可以测试配置文件语法,如果有错误会直接报出。

更深入的一层是检查SSH密钥权限。重启后/home目录下的.ssh文件夹权限可能因挂载问题发生变化。私钥文件权限必须是600,.ssh目录权限必须是700,authorized_keys文件权限必须是644。权限过宽会导致SSH拒绝使用密钥认证,系统可能回退到密码认证,而你完全没察觉。用find /home -name authorized_keys -exec ls -la {} \;批量检查所有用户的密钥文件权限。

审计正在监听的网络端口

执行sudo ss -tlnp查看所有TCP监听端口。对比你预期的服务清单,任何多余的监听端口都可能是安全隐患。重点关注监听在0.0.0.0上的服务,这意味着对所有网络接口开放。如果看到127.0.0.1:631这样的CUPS打印服务监听,而你根本不需要打印功能,立即用sudo systemctl disable --now cups卸载并禁用。

同时检查UDP端口sudo ss -ulnp。UDP端口常被忽视,但DNS服务、NTP服务、某些监控代理都通过UDP通信。特别留意高端口范围的监听,可能是恶意进程留下的后门。结合sudo lsof -i -P -n可以进一步确认每个端口对应的进程名称和PID,交叉验证进程的合法性。

检查自动挂载点的安全属性

重启后/etc/fstab中定义的挂载点会重新挂载,但挂载选项可能被忽略或重置。执行mount | column -t查看所有挂载点及其选项。对于/tmp、/var/tmp这类可写目录,必须确认挂载选项包含noexec、nosuid、nodev。这三个选项能阻止攻击者在临时目录执行恶意程序、利用SUID提权、创建设备文件。如果你的/tmp没有独立分区,至少要用systemd的tmp.mount来强制添加这些选项。

对于NFS或外部存储挂载,检查是否意外以rw模式挂载了只读数据卷。执行cat /proc/mounts比mount命令更准确,因为它显示内核实际使用的挂载参数。如果发现挂载点缺少nosuid选项,而该挂载点又对用户可写,攻击者可以放置一个SUID shell来提权。

验证AppArmor强制策略是否激活

Ubuntu默认启用AppArmor作为强制访问控制系统。重启后执行sudo aa-status查看当前加载的策略和模式。重点看profiles部分,确认关键服务如MySQL、nginx、libvirt的配置文件处于enforce模式而非complain模式。complain模式只记录违规行为但不阻止,等同于没有防护。如果发现某个服务的配置文件被卸载,检查/etc/apparmor.d/目录下对应文件是否存在,然后用sudo aa-enforce重新加载。

另一个容易被忽略的点是AppArmor对容器的影响。如果你使用LXD或LXC,每个容器的AppArmor配置文件在重启后需要重新生成。执行sudo lxc profile show default查看默认配置,确认security.privileged为false,否则容器内进程可以绕过AppArmor限制。

检查内核安全参数是否持久化

很多人通过sysctl命令临时修改内核参数,但忘记写入/etc/sysctl.conf或/etc/sysctl.d/下的配置文件,重启后参数全部丢失。执行sudo sysctl -a | grep -E "net.ipv4.tcp_syncookies|net.ipv4.ip_forward|kernel.randomize_va_space|kernel.kptr_restrict|net.ipv4.conf.all.rp_filter"逐项验证。net.ipv4.tcp_syncookies应该为1,防止SYN Flood攻击。kernel.randomize_va_space必须为2,确保地址空间布局随机化完全启用。net.ipv4.ip_forward除非你明确需要做路由转发,否则应为0。

还要检查/proc/sys/下的运行时参数是否与sysctl配置一致。某些安全模块如SELinux或内核启动参数中的安全选项,sysctl无法覆盖。执行cat /proc/cmdline查看内核启动参数,确认是否有apparmor=1 security=apparmor这类强制启用安全模块的参数。

审查定时任务和启动脚本的完整性

重启后所有cron任务和systemd timer会重新激活,这是攻击者最常植入持久化后门的地方。逐一检查/etc/crontab、/etc/cron.d/、/var/spool/cron/crontabs/目录下的文件内容,用sudo grep -r "curl\|wget\|nc\|bash -i\|python -c" /etc/cron* /var/spool/cron/搜索可疑的下载或反弹shell命令。同时检查系统级systemd服务sudo systemctl list-unit-files --type=service --state=enabled,对每个已启用的服务用sudo systemctl cat 服务名查看具体执行内容,确认没有异常的ExecStart指令。

特别注意用户级的systemd服务,它们存放在~/.config/systemd/user/目录下,可以在用户登录时自动启动,且不需要root权限。用find /home -path "*/.config/systemd/user/*" -type f查找所有用户级服务文件,逐个审查。

检查日志审计系统是否正常运行

重启后rsyslog或systemd-journald可能因磁盘空间不足或配置错误而停止记录。执行sudo systemctl status rsyslog systemd-journald确认两个日志服务都在运行。然后用logger "security check after reboot"生成一条测试日志,再用sudo journalctl -n 10或sudo tail /var/log/syslog确认日志成功写入。如果日志系统失效,所有安全事件都将丢失,入侵检测形同虚设。

检查auditd审计框架的状态sudo auditctl -s,确认enabled值为1,且pid显示进程号。如果auditd未运行,执行sudo systemctl enable --now auditd。同时检查/etc/audit/rules.d/下的审计规则是否在重启后正确加载,用sudo auditctl -l列出当前生效的规则,对比你的规则文件确认无遗漏。

自动化检查脚本的实现思路

手动逐项检查效率低且容易遗漏,建议将上述检查点固化为一个bash脚本,放在/etc/rc.local或通过systemd的oneshot服务在每次启动后自动执行,结果输出到日志文件或通过消息推送通知管理员。脚本的核心逻辑可以这样组织:

#!/bin/bash
REPORT="/var/log/security-check-$(date +%Y%m%d-%H%M%S).log"
echo "=== Security Check Report $(date) ===" > $REPORT

# 防火墙检查
ufw status | grep -q "active" || echo "[FAIL] UFW is inactive" >> $REPORT
iptables -L INPUT | grep -q "policy DROP" || echo "[WARN] INPUT policy is not DROP" >> $REPORT

# SSH配置检查
grep -q "^PermitRootLogin no" /etc/ssh/sshd_config || echo "[FAIL] Root login permitted" >> $REPORT
grep -q "^PasswordAuthentication no" /etc/ssh/sshd_config || echo "[WARN] Password auth enabled" >> $REPORT

# 异常端口检查
KNOWN_PORTS="22|80|443|3306|6379"
ss -tlnp | grep -vE "($KNOWN_PORTS)" | awk '{print $4}' >> $REPORT

# 挂载选项检查
mount | grep "/tmp" | grep -q "noexec" || echo "[FAIL] /tmp missing noexec" >> $REPORT

# AppArmor检查
aa-status | grep -q "0 profiles are in complain mode" || echo "[WARN] AppArmor has complain mode profiles" >> $REPORT

# 内核参数检查
[ "$(sysctl -n kernel.randomize_va_space)" -eq 2 ] || echo "[FAIL] ASLR not fully enabled" >> $REPORT

echo "Check completed. Report saved to $REPORT"

这个脚本可以根据实际环境扩展,加入更多检查项如文件完整性校验、特定进程存活检测。关键是要让脚本在系统启动的最后阶段执行,确保所有服务都已加载完毕。使用systemd服务实现时,设置After=network.target multi-user.target保证网络和服务就绪后再检查。

建立重启后的基线对比机制

单次检查只能发现明显异常,更隐蔽的安全问题需要对比历史基线才能发现。每次重启后生成一份系统状态快照,包含进程列表、监听端口、内核模块、加载的systemd服务、iptables规则等,与上一次快照做diff对比。用ps auxf > /var/backups/ps-snapshot.txt生成进程快照,用ss -tlnp > /var/backups/port-snapshot.txt生成端口快照,然后用diff命令对比变化。任何新增的进程或端口都应触发人工审查。

内核模块的加载情况尤其值得关注,因为rootkit常以内核模块形式注入。执行lsmod > /var/backups/lsmod-snapshot.txt保存模块列表,重启后对比。如果出现不明模块,立即用modinfo 模块名查看详细信息,并用sudo rmmod强制卸载可疑模块。

这套检查流程执行一遍大约需要三到五分钟,但能避免因配置丢失或服务异常导致的安全敞口。把检查结果集成到监控告警系统里,比如通过自定义的Prometheus exporter暴露检查指标,或者直接让脚本在发现严重问题时调用Webhook发送告警。安全状态检查不是一次性工作,而是每次重启后的固定动作,形成肌肉记忆才算真正落地。