userdel -r 不够,必须分三步走:先终止所有关联进程(如pkill -u、loginctl terminate-user),再执行userdel -r删账户,最后按uid扫描并清理cron、sudoers、ssh密钥及systemd --user等残留。

直接说结论:userdel -r 不够,必须分三步走——先杀进程、再删账户、最后扫残留。 你看到的“删除成功”,往往只是 /etc/passwd 里那行没了;真正的风险藏在 /var/spool/cron/username、/etc/sudoers.d/ 下的授权条目、甚至 root 用户的 ~/.ssh/authorized_keys 里。
为什么 userdel -r 会漏掉关键残留
它只按预设路径删:/home/username、/var/spool/mail/username(或 /var/mail/username),但现代系统里用户痕迹更分散:
-
userdel -r不处理/var/spool/cron/username—— 这个文件即使用户已删,cron daemon 仍会尝试加载并报错 -
sudoers文件里的%devs ALL=(ALL) NOPASSWD: /usr/bin/systemctl这类组授权不会被自动清理,只要组存在,权限就生效 - SSH 公钥可能写在
/root/.ssh/authorized_keys或/etc/ssh/authorized_keys中,userdel -r完全不碰这些位置 - systemd --user 服务(如
~/.config/systemd/user/*.service)不会被扫描,重启后可能以 UID 启动失败并卡住 journal
删除前必须终止所有关联进程
别信 “用户没登录” 就安全。nohup、screen、systemd --user、Docker 容器内进程都可能挂着 UID 继续跑:
在无 root/sudo 权限的环境(云容器、VPS、隔离主机)中安装并配置 OpenClaw 浏览器工具的 headless Chrome。适用场景:...
- 查所有归属该用户的进程:
ps -eo uid,user,comm,args | awk '$1 == "$(id -u username)" {print}' - 终止常规进程:
pkill -u username(注意:不杀 init 进程,PPID=1 的跳过) - 终结 login session 和用户级服务:
loginctl terminate-user username(systemd 系统必备) - 手动检查孤儿 socket:
lsof -U -a -u username(看有没有未关闭的 Unix domain socket)
删完账户后必须人工核查的 4 个位置
执行 userdel -r username 后,立刻验证以下位置是否清空,否则等于留后门:
-
/var/spool/cron/username:直接rm -f /var/spool/cron/username,别等 cron 自己发现 -
grep -r "username\|%username" /etc/sudoers* 2>/dev/null:重点看/etc/sudoers.d/下独立文件,用visudo编辑删除整行 -
find /root /etc/ssh -name "authorized_keys" -exec grep -l "ssh-rsa.*username" {} \; 2>/dev/null:匹配公钥注释字段,删对应行 -
find / -xdev -user $(id -u username) 2>/dev/null:按 UID 扫全盘(-xdev防跨挂载点),重点看/tmp、/var/tmp、/run下的临时文件
最常被跳过的其实是按 UID 扫描这一步——用户名删了,但文件属主变成数字 UID,ls -l 看不到名字,却仍能被进程读写。不扫 UID,就永远不知道 /var/log/journal/ 里有没有残留的用户服务日志目录,或者 /run/user/1001 下有没有没卸载的 dbus session。










