FAQ-2:权限与用户管理常见问题

预计阅读时间:14 分钟

📖 目录

FAQ-2:权限与用户管理常见问题(Q16-Q28)

问题速查表

问题章节
Q16: Permission denied 怎么解决?Q16
Q17: sudo 提示 not in sudoers file?Q17
Q18: 如何让多个用户共享目录?Q18
Q19: 如何防止用户删除不属于自己的文件?Q19
Q20: 如何设置默认文件权限?Q20
Q21: 为什么 chmod 777 不生效?Q21
Q22: 如何查看谁在占用文件?Q22
Q23: 如何限制用户只能执行特定 sudo 命令?Q23
Q24: 如何查找某用户的所有文件?Q24
Q25: 如何批量修改权限?Q25
Q26: 如何以其他用户身份运行程序?Q26
Q27: 如何锁定/解锁用户?Q27
Q28: 如何设置密码过期策略?Q28

Q16: Permission denied 怎么解决?

这是 Linux 中最常见的错误之一,意思是当前用户没有对目标文件或目录的所需权限。Linux 权限分三级:属主(u)、属组(g)、其他用户(o),每级有读(r=4)、写(w=2)、执行(x=1)三种权限。

# 第一步:查看文件权限
ls -la /path/to/file
# 输出示例:-rw-r--r-- 1 root root 1024 Jun 15 10:00 file.txt
#           含义:属主可读写,属组只读,其他用户只读

# 根据情况修复:
chmod +r file           # 添加读权限
chmod +x dir            # 添加执行权限(目录的 x 表示可进入)
sudo chown user file    # 修改文件属主(需要 root)

Q17: sudo 提示 not in sudoers file?

sudo(Super User DO)允许普通用户以 root 身份执行命令。需要将用户加入 sudo 组或在 /etc/sudoers 中配置。

# 将用户加入 sudo 组(推荐方式)
# Debian/Ubuntu 系统的 sudo 组名为 sudo
sudo usermod -aG sudo username

# CentOS/RHEL 系统的 sudo 组名为 wheel
sudo usermod -aG wheel username

# -a:追加(不加 -a 会覆盖原有组)
# -G:指定附加组

# 修改后需要重新登录才能生效
# 或用 newgrp sudo 立即切换组

Q18: 如何让多个用户共享目录?

通过创建共享组并设置 SGID(Set Group ID)位,让新创建的文件自动继承目录的属组。

# 1. 创建共享组
sudo groupadd shared

# 2. 将用户加入组
sudo usermod -aG shared user1 user2

# 3. 设置目录属组
sudo chown -R :shared /shared/dir

# 4. 设置 SGID 位(2775 中的 2)
# SGID 作用:目录下新建文件自动继承目录的属组(而非创建者的主组)
# 775:属主 rwx,属组 rwx,其他 rx
sudo chmod -R 2775 /shared/dir

Q19: 如何防止用户删除不属于自己的文件?

使用 Sticky Bit(粘滞位),目录中的文件只有属主才能删除。

# 设置 Sticky Bit(1777 中的 1)
# 1777:Sticky + rwxrwxrwx
# 典型场景:/tmp 目录
chmod 1777 /shared/dir

# 验证:ls -ld 显示末尾的 t 表示 Sticky 已设置
ls -ld /shared/dir
# drwxrwxrwt 2 root root 4096 Jun 15 10:00 /shared/dir
#                                         ↑ t = Sticky Bit

Q20: 如何设置默认文件权限?

umask(User Mask)定义新建文件/目录时"掩掉"的权限。文件默认最大权限 666,目录 777,减去 umask 值就是实际权限。

# umask 022:新建文件 644(rw-r--r--),目录 755(rwxr-xr-x)
umask 022

# umask 027:新建文件 640(rw-r-----),目录 750(rwxr-x---)
# 更严格,其他用户无法读取
umask 027

# 计算方法:文件 666 - 022 = 644,目录 777 - 022 = 755
# 永久生效:写入 ~/.bashrc 或 /etc/profile

Q21: 为什么 chmod 777 不生效?

chmod 设置的是 Unix 权限,但在以下场景可能"不生效":

# 场景一:文件系统不支持 Unix 权限
# NTFS/FAT32/exFAT 挂载的分区,权限由 mount 选项控制
mount | grep /mnt/windows
# /dev/sda1 on /mnt/windows type ntfs (rw,uid=1000,gid=1000)

# 场景二:SELinux/AppArmor 安全策略阻止
# 即使 Unix 权限允许,SELinux 仍可能拒绝访问
ls -Z /path/to/file    # 查看 SELinux 上下文
getenforce             # 查看 SELinux 模式(Enforcing/Permissive/Disabled)

# 场景三:文件系统只读挂载
mount | grep "ro,"
# /dev/sdb1 on /data type ext4 (ro,...)  ← 只读挂载

Q22: 如何查看谁在占用文件?

# lsof:列出打开文件的进程
# /path/to/file 路径可以是任何打开的文件
lsof /path/to/file

# fuser:更简洁地查看占用文件的进程 PID
# -v:详细输出(显示进程名和用户)
fuser -v /path/to/file

# 终止占用进程:
fuser -k /path/to/file    # -k 发送 SIGKILL 信号

Q23: 如何限制用户只能执行特定 sudo 命令?

通过 /etc/sudoers 文件的命令白名单,限制用户的 sudo 权限范围,遵循最小权限原则。

# 用 visudo 编辑(会检查语法,避免锁死自己)
sudo visudo

# 允许用户执行特定命令(绝对路径)
# 格式:用户名 主机=(运行身份) 命令列表
username ALL=(ALL) /usr/bin/systemctl restart nginx, /usr/bin/systemctl restart apache2

# 允许用户不输密码执行特定命令(NOPASSWD)
username ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx

Q24: 如何查找某用户的所有文件?

# find -user:按文件属主查找
# 2>/dev/null:抑制权限不足的报错(扫描系统目录时必须加)
find / -user username 2>/dev/null

# 统计某用户的文件数量和总大小
find / -user username 2>/dev/null | wc -l              # 文件数
find / -user username -exec du -ch {} + 2>/dev/null | tail -1  # 总大小

Q25: 如何批量修改权限?

# 将所有文件设为 644(属主读写,其他只读)
find . -type f -exec chmod 644 {} +

# 将所有目录设为 755(属主全权限,其他可进入可读)
find . -type d -exec chmod 755 {} +

# + 和 \; 的区别:
# + 把多个文件一次性传给 chmod(效率高)
# \; 每个文件单独执行一次 chmod(效率低)

Q26: 如何以其他用户身份运行程序?

# sudo -u:以指定用户身份执行命令
sudo -u www-data command

# systemd 服务中指定运行用户
# 在 [Service] 段中添加:
# User=www-data
# Group=www-data

Q27: 如何锁定/解锁用户?

# 锁定用户(密码登录失效,但密钥登录可能仍可用)
sudo passwd -l username

# 解锁用户
sudo passwd -u username

# 更彻底:将 shell 设为 nologin(禁止所有交互登录)
sudo usermod -s /usr/sbin/nologin username
# nologin 登录时提示 "This account is currently not available"

Q28: 如何设置密码过期策略?

# 查看密码策略
sudo chage -l username

# 设置密码最长有效期为 90 天
sudo chage -M 90 username

# 设置密码最短修改间隔为 7 天
sudo chage -m 7 username

# 设置密码过期前 14 天提醒
sudo chage -W 14 username

# 强制用户下次登录时修改密码
sudo chage -d 0 username

真实案例

案例 A:chmod -R 777 误操作导致 SSH 密钥登录失败

现象:运维在排查 Web 应用权限问题时,执行了 chmod -R 777 /home/www,随后该用户的 SSH 密钥登录立即失败。

# 报错
$ ssh deploy@server
Permission denied (publickey).

# 查看权限
$ ls -ld ~/.ssh
drwxrwxrwx 2 deploy deploy 4096 Jun 15 10:00 /home/deploy/.ssh

$ ls -la ~/.ssh/authorized_keys
-rwxrwxrwx 1 deploy deploy 389 Jun 15 10:00 /home/deploy/.ssh/authorized_keys

根因:sshd 的 StrictModes 机制要求 ~/.ssh 目录权限不能超过 700,authorized_keys 不能超过 600。权限 777 意味着其他用户可以修改密钥文件,sshd 出于安全考虑直接拒绝。

修复chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys。教训:-R 777 是运维大忌,应该精确设置目标目录的权限。

案例 B:sudo 权限配置错误导致用户可以执行任意 root 命令

现象:开发人员在 sudoers 中配置了 deploy ALL=(ALL) /usr/bin/vim,但 vim 可以执行 :!bash 直接获得 root shell。

根因:sudo 权限只限制了启动命令,但 vim 等交互式程序可以通过 :!command:set shell=/bin/bash 执行任意命令。这类程序在 sudo 白名单中非常危险。

修复:不要将 vim、less、more、man 等可执行 shell 命令的程序加入 sudo 白名单。如果必须允许编辑配置文件,用 sudoeditsudo -e)替代。

案例 C:SGID 位设置错误导致新建文件属组混乱

现象:共享目录 /data/shared 设置了 chmod 2775,但 user1 创建的文件属组仍然显示 user1 的主组,而非 shared 组。

排查:检查发现 user1 的主组和 shared 组名相同但 GID 不同——一个是旧的 1001,一个是新建的 1002。

修复sudo usermod -g shared user1 将用户主组设为 shared 组,或 sudo usermod -aG shared user1 确保用户在 shared 组中。SGID 只在用户属于该组时才生效。

预防措施

  • 永远不要对生产环境执行 chmod -R 777,用精确权限(如 755、644)替代
  • sudoers 白名单避免添加 vim、less、bash 等可执行 shell 命令的程序,优先使用 sudoedit
  • 共享目录创建前先确认所有用户的 GID 一致,用 id username 检查
  • 定期审计 sudoers 配置:sudo -l -U username 查看用户的 sudo 权限
  • umask 建议在 /etc/profile 中全局设置,确保所有用户默认权限一致
  • SSH 相关目录权限基线:~/.ssh 为 700,authorized_keys 为 600,HOME 目录不超过 755
  • 生产环境避免直接使用 root 账户,通过 sudo 和专用运维账户进行操作审计
  • Web 应用上传目录设置 SGID(chmod 2775),确保上传文件属组正确
  • 密码策略建议:最短 8 位、最长 90 天过期、禁止重复使用最近 5 次密码
  • 定期审计系统中设置了 SUID/SGID 的文件:find / -perm -4000 -o -perm -2000 2>/dev/null,移除不必要的 SUID 位。SUID 文件是提权攻击的常见入口
  • 共享目录创建前用 id username 确认所有用户的 GID 一致,避免 SGID 失效
  • Web 应用上传目录设置 SGID(chmod 2775),确保上传文件属组正确

案例 D:ACL 权限实现精细化文件共享

现象:需要让 user3 对 /data/project 目录有读写权限,但 user3 不属于该目录的属组,且不方便修改属组。

# 查看当前 ACL
$ getfacl /data/project
# 只有 owner 和 group 的权限

# 设置 ACL:给 user3 添加读写权限
$ sudo setfacl -m u:user3:rwx /data/project

# 设置默认 ACL(新建文件自动继承)
$ sudo setfacl -d -m u:user3:rwx /data/project

# 验证 ACL
$ getfacl /data/project
# user:user3:rwx
# default:user:user3:rwx

# 查看带 ACL 的文件权限(+ 号表示有 ACL)
$ ls -la /data/
drwxrwxr-x+ 2 root root 4096 Jun 15 10:00 project

根因:传统 Unix 权限只有 owner/group/other 三级,无法为特定用户单独授权。ACL(Access Control List)支持任意数量的用户/组权限条目,是传统权限的超集。ext4 和 xfs 文件系统默认支持 ACL,但需要在挂载选项中启用(acl)。

修复:使用 setfacl -m 添加 ACL 条目,-d 设置默认 ACL 让新文件自动继承。文件系统需支持 ACL(ext4/xfs 默认支持),挂载选项需包含 acl

案例 E:umask 导致 Web 应用权限不足

现象:Nginx 上传文件后,PHP-FPM 无法读取上传的文件,报 Permission denied

# 检查上传文件权限
$ ls -la /var/www/uploads/
-rw-rw-r-- 1 www-data www-data 12345 Jun 15 10:00 photo.jpg

# PHP-FPM 以 php-fpm 用户运行
# www-data 和 php-fpm 不同组,other 权限只有 r--(不可写)
# 且上传目录的 SGID 未设置

# 检查当前 umask
$ umask
0022    # 新文件默认 644(rw-r--r--)

# 解决方案一:设置上传目录 SGID
$ sudo chmod 2775 /var/www/uploads
# 新文件自动继承 www-data 属组

# 解决方案二:配置 PHP-FPM 用户
# /etc/php/8.1/fpm/pool.d/www.conf
listen.owner = www-data
listen.group = www-data

# 验证配置
$ php -i | grep "user"
Process Owner => www-data

# umask 永久设置
$ echo "umask 022" >> /etc/profile

根因:Web 服务器用户和应用运行用户不同组,上传目录未设置 SGID,新文件属组为上传者(www-data)。PHP-FPM 进程以独立用户运行,无法读取其他用户的文件。umask 022 导致新文件权限为 644,other 用户只有读权限。

修复:设置上传目录 SGID chmod 2775 /var/www/uploads,或配置 PHP-FPM 的 listen.owner = www-data 让 FPM 进程继承 Nginx 的组权限。使用 ACL 为特定用户授权也是一种方案。确保上传目录的 umask 允许组写权限。

案例 F:umount 报 "target is busy" 无法卸载

现象:执行 sudo umount /mnt/dataumount: /mnt/data: target is busy

# 查看谁在使用挂载点
$ sudo fuser -mv /mnt/data
                     USER    PID ACCESS COMMAND
/mnt/data:           root  12345 f.... bash

# 或用 lsof 查看
$ sudo lsof +f -- /mnt/data
COMMAND  PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
bash    12345 root  cwd    DIR    8,1     4096    2 /mnt/data

# 终止占用进程
$ sudo fuser -k /mnt/data

# 或切换工作目录后再卸载
$ cd / && sudo umount /mnt/data

# 紧急情况:lazy umount(延迟卸载)
$ sudo umount -l /mnt/data
# 不再有新进程能访问该挂载点,等现有进程结束后自动卸载

根因:有进程的工作目录(cwd)在挂载点内,或打开了挂载点内的文件。内核不允许卸载活跃的文件系统,否则可能导致数据丢失。

修复:终止占用进程 sudo fuser -k /mnt/data,或切换到其他目录后再卸载。紧急情况用 umount -l(lazy umount)延迟卸载。用 fuser -mvlsof +f 快速定位占用进程。

案例 G:SUID 位的安全风险——find 提权漏洞

现象:攻击者发现系统上 /usr/bin/find 被设置了 SUID 位,利用 find -exec /bin/sh -p \; 直接获得 root shell。

# 查找所有 SUID 文件
$ find / -perm -4000 -type f 2>/dev/null
/usr/bin/passwd
/usr/bin/sudo
/usr/bin/find          ← 危险!不应有 SUID

# 攻击者利用
$ find -exec /bin/sh -p \;
# sh-5.1# whoami
root

# 防御:定期审计 SUID 文件并移除不必要的
$ sudo find / -perm -4000 -type f -exec ls -la {} \; 2>/dev/null
# 检查每个 SUID 文件是否确实需要

根因:管理员误操作 chmod u+s /usr/bin/find,find 的 -exec 选项在 SUID 模式下以 root 权限执行任意命令。类似风险的还有 vimlessawk 等可执行命令的程序。

修复chmod u-s /usr/bin/find 移除 SUID 位。定期审计:find / -perm -4000 -type f 2>/dev/null,移除不必要的 SUID 文件。使用 apt list --installed 2>/dev/null | xargs -I {} dpkg -L {} 2>/dev/null | grep bin 检查哪些包安装了 SUID 文件。系统安全加固时应将 SUID 文件清单纳入基线管理。

案例 H:passwd -l 锁定用户后 SSH 密钥登录仍可用

现象:用 sudo passwd -l deploy 锁定用户后,发现该用户仍能通过 SSH 密钥登录服务器。

# 锁定用户密码
$ sudo passwd -l deploy
passwd: password changed.

# 但 SSH 密钥登录仍然可用
$ ssh deploy@server    # 成功登录

# 查看用户状态
$ grep deploy /etc/shadow
deploy:!:19862:0:99999:7:::    # 密码字段为 ! 但密钥认证绕过了密码检查

根因passwd -l 只锁定密码认证,不影响 SSH 公钥认证。SSH 密钥认证在 authorized_keys 阶段完成,不经过 /etc/shadow 密码检查。

修复:要完全禁止登录,需将 shell 设为 nologin:sudo usermod -s /usr/sbin/nologin deploy。同时移除 ~/.ssh/authorized_keys 中的公钥。双重锁定才能确保账户完全不可用。

案例 I:usermod -G 覆盖导致用户丢失辅助组

现象:管理员将用户加入 docker 组:usermod -G docker deploy,结果用户丢失了原有的 sudo 和 www-data 组权限。

# 修改前用户的组
$ id deploy
uid=1000(deploy) gid=1000(deploy) groups=1000(deploy),27(sudo),33(www-data),999(docker)

# 执行 usermod -G docker deploy 后
$ id deploy
uid=1000(deploy) gid=1000(deploy) groups=1000(deploy),999(docker)
# sudo 和 www-data 组丢失了!

# 正确做法:用 -aG 追加
$ sudo usermod -aG docker deploy
$ id deploy
uid=1000(deploy) gid=1000(deploy) groups=1000(deploy),27(sudo),33(www-data),999(docker)

根因usermod -G(不带 -a)会覆盖用户的所有附加组,只保留 -G 指定的组。这是一个常见的误操作,可能导致用户丢失关键权限。

修复-a 表示追加(append),-aG 组合使用才能在保留原有组的基础上添加新组。修改用户组权限前用 id username 确认当前组列表,修改后再次确认。

案例 J:chown 递归修改 /home 导致用户无法登录

现象:执行 chown -R www-data:www-data /home 后,所有用户无法通过 SSH 登录,报 Permission denied (publickey)

# 查看 home 目录权限
$ ls -ld /home/deploy
drwxr-xr-x 3 www-data www-data 4096 Jun 15 10:00 /home/deploy

# SSH 要求 HOME 目录属主必须是用户本人
# 权限 755 但属主是 www-data,sshd 拒绝登录

# 修复:恢复 home 目录属主
$ sudo chown -R deploy:deploy /home/deploy

# 正确做法:精确指定目标,不要递归整个 /home
$ sudo chown -R www-data:www-data /home/www
# 只修改 /home/www,不影响其他用户目录

根因chown -R 递归修改目录所有内容,包括其他用户的 HOME 目录。SSH 的 StrictModes 要求用户 HOME 目录的属主必须是该用户,否则拒绝登录。

修复chown -R 只针对特定目标目录,不要递归到 /home。修改后用 ls -ld /home/* 检查所有用户目录的属主是否正确。误操作后立即 chown 恢复。

延伸阅读

↑ 回到顶部