Debian系统装完后默认会创建很多服务、setuid程序和宽松的目录权限,这些默认值面向兼容性而非安全性。权限最小化的核心不是“删掉所有东西”,而是让每个进程、每个用户、每个文件只拥有完成自身任务所必需的最小权限集合。先检查当前系统里哪些程序带setuid位,这是提权攻击最常利用的点。

执行以下命令列出所有setuid和setgid文件:

find / -perm -4000 -o -perm -2000 -type f 2>/dev/null

你会看到类似/usr/bin/passwd、/usr/bin/sudo、/usr/bin/chsh等。其中很多是必要的,但像/usr/bin/chfn、/usr/bin/mount、/usr/bin/umount这些在服务器场景下几乎用不到。对于不需要的setuid程序,直接移除其特殊权限位:

chmod u-s /usr/bin/chfn
chmod u-s /usr/bin/chsh
chmod u-s /usr/bin/mount
chmod u-s /usr/bin/umount

注意不要移除/usr/bin/sudo和/usr/bin/passwd的setuid位,否则用户改密码和提权操作会受影响。如果服务器上没有普通用户需要改密码,可以考虑用chmod u-s /usr/bin/passwd,但前提是你有root的物理或带外管理通道,否则一旦丢失root密码将无法恢复。

服务账户与用户权限隔离

Debian安装服务时会自动创建对应的系统用户,比如www-data、mysql、postgres等。这些账户默认shell通常是/usr/sbin/nologin或/bin/false,但检查一下是否所有服务账户都无法登录:

awk -F: '$7 !~ /(nologin|false)/ {print $1 ":" $7}' /etc/passwd

输出里除了root和你自己创建的登录用户外,不应有其他服务账户。如果发现某个服务账户shell是/bin/bash,立即用chsh -s /usr/sbin/nologin 用户名修改。同时检查/etc/shadow中这些账户的密码字段是否为*或!,确保它们没有可用密码。

对于Web服务,www-data用户不应该拥有网站目录的写权限。很多教程为了方便让用户直接chown -R www-data:www-data /var/www,这是非常危险的做法。一旦Web应用出现任意文件写入漏洞,攻击者就能直接植入webshell。正确做法是:网站文件属主为普通部署用户,组为www-data,目录权限750,文件权限640,只有需要上传的目录(如uploads、cache)才给www-data写权限,且这些目录应禁止执行PHP。

chown -R deploy:www-data /var/www/site
find /var/www/site -type d -exec chmod 750 {} \;
find /var/www/site -type f -exec chmod 640 {} \;
chmod 770 /var/www/site/uploads

sudo权限的精细化控制

默认情况下Debian可能将初始用户加入sudo组,该组成员可以执行任何命令。如果这台服务器有多人管理,应该按职责拆分sudo权限。编辑/etc/sudoers时务必使用visudo命令,避免语法错误导致无法提权。例如只允许某个用户重启nginx和查看系统日志:

deploy ALL=(root) /usr/sbin/nginx -s reload, /usr/bin/journalctl

不要给普通管理员ALL=(ALL:ALL) ALL的权限,除非此人就是系统所有者。对于需要临时提权的场景,可以配置sudo命令需要密码,并设置timestamp_timeout=0,让每次sudo都要重新输入密码。

文件系统挂载选项加固

权限最小化也体现在文件系统层面。/tmp、/var/tmp、/dev/shm这些目录是所有用户可写的,攻击者常在这些位置放置恶意脚本或可执行文件。在/etc/fstab中为这些挂载点添加noexec、nosuid、nodev选项:

tmpfs /tmp tmpfs defaults,noexec,nosuid,nodev 0 0
tmpfs /var/tmp tmpfs defaults,noexec,nosuid,nodev 0 0

如果/tmp不是独立挂载点,可以创建一个tmpfs挂载。对于/var分区,如果不需要执行其中的程序,也可以加noexec,但要注意有些包管理器会在/var/tmp下执行脚本,加noexec可能导致安装失败。建议先在测试环境验证。

/home分区加nosuid和nodev是必要的,防止用户在自己的目录里放置setuid程序。如果/home是独立分区,在fstab中修改:

/dev/sda3 /home ext4 defaults,nosuid,nodev 0 2

内核参数与进程限制

权限最小化还涉及内核对进程行为的约束。在/etc/sysctl.conf或/etc/sysctl.d/99-hardening.conf中添加以下参数:

kernel.kptr_restrict=2
kernel.dmesg_restrict=1
kernel.unprivileged_bpf_disabled=1
kernel.yama.ptrace_scope=2
fs.protected_hardlinks=1
fs.protected_symlinks=1

kernel.kptr_restrict=2防止普通用户通过/proc/kallsyms读取内核指针地址,kernel.dmesg_restrict=1限制普通用户查看内核日志。kernel.unprivileged_bpf_disabled=1禁止非特权用户加载BPF程序,这在容器逃逸和内核提权中经常被利用。fs.protected_hardlinks和fs.protected_symlinks防止普通用户在可写目录中创建指向敏感文件的硬链接或符号链接来绕过权限检查。

应用这些参数后执行sysctl -p使其生效。

服务自身的权限降级

很多服务默认以root启动,然后自行降权到低权限用户运行。但有些服务配置不当会一直以root运行。检查当前所有监听端口的进程及其运行用户:

ss -tulpn | awk '{print $1, $5, $7}'

如果发现某个服务以root身份监听端口,检查该服务的配置文件是否支持user指令。例如Nginx主进程需要root绑定80/443端口,但worker进程应以www-data运行,这在nginx.conf中通过user www-data;指定。Apache同理。对于自定义的Node.js、Python服务,绝不要用root直接运行,应使用systemd的User=和Group=指令降权。

systemd服务单元文件示例:

[Service]
User=appuser
Group=appgroup
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX

NoNewPrivileges=true阻止服务进程通过setuid或capabilities获取新权限,即使进程被攻破也难以提权。ProtectSystem=strict让整个文件系统对服务只读,只有明确允许的目录可写。PrivateTmp=true给服务一个独立的/tmp目录,防止与其他进程共享临时文件。

移除不必要的软件包与服务

每个安装的软件包都可能引入新的攻击面。Debian最小化安装后,用以下命令列出所有已安装的包,逐个审查是否真的需要:

dpkg --get-selections | grep -v deinstall

常见的可移除项包括:cups打印服务、avahi-daemon零配置网络、bluetooth蓝牙、ModemManager调制解调器管理、whoopsie错误报告。这些在服务器上毫无用处,直接apt purge移除:

apt purge cups avahi-daemon bluetooth modemmanager whoopsie -y
apt autoremove --purge -y

同时检查systemd中已启用但不需要的服务:

systemctl list-unit-files --state=enabled

对于不需要的服务,用systemctl disable --now 服务名停用并禁止开机启动。

SSH权限收敛

SSH是服务器最核心的远程管理入口,其权限配置直接影响系统安全。编辑/etc/ssh/sshd_config,至少做以下修改:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AllowUsers deploy
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2

PermitRootLogin no禁止root直接SSH登录,所有管理操作通过普通用户sudo完成,这样审计日志中能明确追踪到具体操作者。PasswordAuthentication no禁用密码登录,强制使用密钥认证,消除暴力破解风险。AllowUsers明确列出允许登录的用户名,其他用户即使有合法密钥也无法登录。

修改后重启sshd服务:systemctl restart sshd。注意在修改前确保你当前的SSH会话使用密钥认证且用户已在AllowUsers列表中,否则可能把自己锁在外面。

日志与审计

权限最小化配置完成后,需要持续监控权限变更和异常行为。安装auditd并配置关键文件监控:

apt install auditd -y
auditctl -w /etc/passwd -p wa -k identity
auditctl -w /etc/sudoers -p wa -k sudoers
auditctl -w /etc/ssh/sshd_config -p wa -k sshd
auditctl -w /var/www -p wa -k webroot

这些规则会记录对密码文件、sudo配置、SSH配置和网站目录的任何写入操作。当系统被入侵或配置被篡改时,审计日志能提供关键线索。用ausearch -k identity查看相关记录。

同时确保/var/log目录权限正确,普通用户无法读取或修改日志文件:

chmod 750 /var/log
chmod 640 /var/log/syslog /var/log/auth.log

权限最小化不是一次性操作,而是持续的过程。每次安装新软件、添加新用户、部署新服务时,都要重新审视权限边界。定期用debsecan或debsecan的替代工具检查已安装包的安全公告,及时修补漏洞。权限配置越严格,攻击者横向移动和提权的空间就越小,即使某个服务被攻破,损失也能控制在最小范围内。