Ubuntu服务器文件系统安全防护的核心不是安装某个工具就完事,而是围绕“谁能碰哪些文件、改了能不能发现、出事能不能恢复”这三个问题建立闭环。默认安装的Ubuntu Server在文件权限、挂载选项、审计能力上都偏宽松,直接跑生产环境等于把数据暴露在低水平风险下。下面从权限模型、关键目录加固、挂载策略、文件完整性监控、ACL与特殊权限、日志与恢复六个层面直接给出可落地的配置方法。

先收紧基础权限模型,别让默认umask拖后腿

Ubuntu Server默认umask是022,意味着新建文件默认权限是644,目录是755。对于多用户环境或Web目录,这会让同组用户甚至其他系统账户读到不该读的内容。检查当前umask值:

umask

建议在/etc/profile和/etc/bash.bashrc中将umask改为027,这样新建文件默认640,目录750,同组可读但不可写,其他用户完全无权限。对于运行PHP、Python等动态应用的目录,umask 027能有效防止webshell写入后扩大访问面。修改后需要重新登录生效。如果某些服务需要更严格策略,可以在systemd服务单元中用UMask=077单独指定。

关键系统目录必须去除可写与可执行叠加风险

/tmp、/var/tmp、/dev/shm这三个目录是攻击者上传脚本、提权、维持会话的高发区。默认/tmp带sticky bit,但仍是全局可写。建议对/tmp和/var/tmp单独分区或至少挂载时加noexec,nosuid,nodev选项。编辑/etc/fstab,找到对应行改为:

tmpfs /tmp tmpfs defaults,noexec,nosuid,nodev,size=2G 0 0

如果是独立分区,写法类似:

/dev/sda3 /tmp ext4 defaults,noexec,nosuid,nodev 0 2

这样即使攻击者上传了恶意二进制文件,也无法在/tmp下直接执行。需要注意,某些软件(如apt升级、部分Java应用)需要在/tmp下执行脚本,部署前应在测试环境验证。如果业务确实需要/tmp可执行,至少保留nosuid和nodev。

用挂载选项锁死系统分区和用户目录

根分区/默认带exec和suid,这是系统运行必需的,但/home、/var/www、/srv等数据分区完全不需要suid和可执行设备文件。在/etc/fstab中为这些分区添加nosuid,nodev,noexec:

/dev/sda4 /home ext4 defaults,nosuid,nodev,noexec 0 2

对于Web目录/var/www,如果确认不需要在目录内执行CGI或二进制,同样加noexec。但很多PHP应用通过php-fpm执行,PHP文件本身不是直接exec,所以noexec不影响PHP运行,反而能阻止webshell落地后执行系统命令。如果使用Python虚拟环境或Node.js,注意noexec会阻止venv/bin下的解释器执行,这类目录应排除或单独挂载。

文件系统属性:用chattr锁住核心配置和日志

权限控制不了root,但chattr的不可变属性连root在未解除前都无法修改。对/etc/passwd、/etc/shadow、/etc/group、/etc/sudoers、/etc/ssh/sshd_config等核心文件设置不可变:

chattr +i /etc/passwd /etc/shadow /etc/group /etc/sudoers

日常维护需要修改时先chattr -i,改完再加回。对日志目录/var/log设置追加属性,防止攻击者清除入侵痕迹:

chattr +a /var/log/syslog /var/log/auth.log

注意chattr在ext4和xfs上支持良好,但在btrfs上部分属性受限。另外,系统更新或用户管理脚本可能因文件不可变而失败,需要提前规划维护窗口。

ACL与特殊权限:精确到用户和组的访问控制

基础权限只有owner/group/other三级,多用户协作或Web目录需要更细粒度。Ubuntu默认支持POSIX ACL。例如给web用户组对/var/www/html递归赋予读写权限,同时保留其他用户只读:

setfacl -R -m g:webadmin:rwx /var/www/html
setfacl -R -m o:rx /var/www/html

查看ACL:

getfacl /var/www/html

特殊权限方面,setuid和setgid是提权重灾区。定期扫描系统中所有setuid/setgid文件:

find / -perm /6000 -type f -exec ls -l {} \; 2>/dev/null

除/usr/bin/passwd、/usr/bin/sudo等必需项外,其他一律去除:

chmod u-s /path/to/file
chmod g-s /path/to/file

特别是/usr/bin/find、/usr/bin/vim等工具如果被设置了setuid,必须立即移除。

文件完整性监控:AIDE部署与告警

权限和属性只能防住一部分,真正的安全需要知道文件是否被篡改。AIDE是Ubuntu仓库自带的文件完整性检查工具,安装后初始化数据库:

apt install aide
aideinit

初始化完成后数据库位于/var/lib/aide/aide.db,建议将数据库文件复制到离线介质保存。日常检查:

aide.wrapper --check

配置/etc/aide/aide.conf可以指定监控哪些目录和属性。至少监控/etc、/bin、/sbin、/usr/bin、/usr/sbin、/var/www、/opt等关键位置。建议设置cron每天凌晨执行检查,并将结果发送到日志系统:

0 3 * * * /usr/bin/aide.wrapper --check | mail -s "AIDE Report" admin@example.com

AIDE的局限是数据库更新需要人工确认,如果系统正常升级后未更新数据库,会产生大量误报。因此每次系统更新后应执行aide.wrapper --update重新生成基线。

加密文件系统与敏感数据隔离

对于数据库目录、用户上传目录、密钥存储目录,建议使用LUKS加密或至少eCryptfs加密。如果服务器支持TPM,可以用系统自带工具绑定密钥。生产环境常见做法是对/var/lib/mysql、/var/lib/postgresql、/etc/ssl/private做单独加密卷。创建LUKS加密卷并挂载:

cryptsetup luksFormat /dev/sdb1
cryptsetup open /dev/sdb1 encrypted_data
mkfs.ext4 /dev/mapper/encrypted_data
mount /dev/mapper/encrypted_data /var/lib/mysql

密钥文件应存放在只有root可读的位置,权限600。如果服务器重启频繁,自动解锁需要将密钥放在initramfs或远程密钥服务器,这会增加复杂度,需要根据业务权衡。

日志与审计:让文件操作可追溯

文件系统安全不仅是阻止访问,还要记录谁在什么时候做了什么。Ubuntu自带auditd可以监控关键文件访问。安装并配置:

apt install auditd
auditctl -w /etc/passwd -p wa -k passwd_changes
auditctl -w /etc/shadow -p wa -k shadow_changes
auditctl -w /var/www/html -p wa -k web_changes

规则持久化写入/etc/audit/rules.d/audit.rules。查看审计日志:

ausearch -k passwd_changes

对于Web应用,还应结合inotify实时监控目录变化。可以用incron或简单的systemd path unit实现。例如监控/var/www/html下新增或修改.php文件:

apt install incron
echo "root IN_CREATE,IN_MODIFY /var/www/html/*.php /usr/local/bin/scan_uploaded_file.sh" >> /etc/incron.d/webmonitor

这样任何新上传的PHP文件都会触发扫描脚本,配合ClamAV或自定义规则可以第一时间发现webshell。

恢复能力:快照与备份策略不可缺

文件系统安全防护的最后一道防线是能恢复。如果服务器跑在LVM上,建议对根分区和数据分区定期做LVM快照:

lvcreate -L 5G -s -n snap_root /dev/vg0/root

快照保留最近3-5份,配合cron自动轮转。对于非LVM环境,使用rsync增量备份到独立存储,并保留文件权限和ACL:

rsync -aAXv --delete /var/www /backup/var/www

备份目录本身应设置严格权限,且备份服务器与生产服务器网络隔离。定期做恢复演练,确认备份数据可用,否则再完善的防护在数据丢失时都是空谈。

日常检查清单与自动化加固

文件系统安全需要持续维护。建议每周执行以下检查:

# 检查异常setuid/setgid文件
find / -perm /6000 -type f 2>/dev/null
# 检查全局可写目录
find / -type d -perm -0002 ! -path "/proc/*" ! -path "/sys/*" 2>/dev/null
# 检查无属主文件
find / -nouser -o -nogroup 2>/dev/null
# 检查隐藏文件
find / -name ".*" -type f 2>/dev/null | grep -v "^/usr/share"

将上述检查写成脚本放入cron,输出重定向到日志。对于新部署的Ubuntu服务器,可以用Ansible或shell脚本一次性完成所有加固项,避免人工遗漏。文件系统安全不是一次性配置,而是与系统生命周期同步的持续过程。