4、Linux 权限隔离:用户、组、文件权限、SUID/SGID/SBIT 以及 Capabilities 机制

权限隔离,说白了就是 Linux 系统的命根子。我见过太多线上事故,都是因为权限没管好。要么是某个脚本意外获得了 root 权限,要么是普通用户能读到不该看的密钥文件。嗯,这一章我们就把 Linux 权限体系彻底讲透。

核心认知:Linux 权限隔离不是单一机制,而是一套层层递进的防御体系。从最基础的 UID/GID,到文件权限位,再到 SUID/SGID/SBIT 特殊位,最后到细粒度的 Capabilities——每一层都在解决上一层的不足。

4.1 用户与组:权限的起点

每个进程在 Linux 里都有三个身份:实际用户(RUID)、有效用户(EUID)、保存用户(SUID)。我刚开始学的时候也搞混过,后来在排查一个提权漏洞时才真正理解它们的区别。

身份类型 含义 典型场景
RUID(实际用户) 启动进程的用户 谁执行的命令
EUID(有效用户) 内核检查权限时用的身份 决定能否读写文件
SUID(保存用户) 用于在特权和非特权之间切换 setuid() 系统调用

组的概念也类似。每个用户至少属于一个主组,还可以加入多个附加组。我个人习惯把服务账号和运维账号分到不同组里,这样审计日志一看就知道是谁干的。

我的经验:创建系统用户时,记得用 --system 或 -r 参数。这样 UID 会落在系统范围(通常 < 1000),不会跟普通用户冲突。我曾经见过一个 MySQL 服务账号 UID 是 1001,结果跟新来的开发人员冲突了,数据库直接连不上。

4.2 文件权限:rwx 的真相

文件权限位大家应该都熟悉,但你真的理解每个位的含义吗?

# 查看文件权限
$ ls -l /etc/shadow
-rw-r----- 1 root shadow 1234 Apr 1 10:00 /etc/shadow

# 权限位分解
# 第1位:文件类型(- 普通文件,d 目录,l 符号链接)
# 第2-4位:所有者权限(rw-)
# 第5-7位:所属组权限(r--)
# 第8-10位:其他人权限(---)

目录的 rwx 跟文件不一样,这里容易踩坑:

  • r(读):能列出目录内容,但不能访问里面的文件
  • w(写):能创建或删除文件,但前提是有 x 权限
  • x(执行):能进入目录(cd),能访问里面的文件

避坑指南:我曾经遇到一个案例,运维把 /home 目录权限设成了 777,结果普通用户能删别人的文件。记住:目录的 w 权限控制的是目录条目本身,不是文件内容。想限制用户只能删自己的文件,得用 sticky bit。

4.3 SUID/SGID/SBIT:特殊权限位

这三个特殊位是权限隔离的关键补充。为什么需要它们?你想想看,普通用户要改密码,但 /etc/shadow 只有 root 能写。怎么办?

答案就是 SUID。当可执行文件设置了 SUID 位,任何用户执行它时,EUID 会变成文件所有者(通常是 root)。

# 查看 SUID 文件
$ find / -perm -4000 -type f 2>/dev/null
/usr/bin/passwd
/usr/bin/su
/usr/bin/sudo

# 设置 SUID
$ chmod u+s /path/to/binary
# 或者用八进制
$ chmod 4755 /path/to/binary
特殊位 八进制值 作用 风险
SUID (Set User ID) 4000 执行时 EUID 变为文件所有者 提权漏洞重灾区
SGID (Set Group ID) 2000 执行时 EGID 变为文件所属组;目录下新建文件继承组 组权限泄露
SBIT (Sticky Bit) 1000 目录下只有文件所有者能删自己的文件 相对安全

关键原则:SUID/SGID 文件越少越好。我每季度都会跑一遍 find / -perm -4000 -o -perm -2000,检查有没有不该出现的特殊权限位。曾经在一个客户环境里发现 /usr/bin/vim 居然有 SUID——这明显是被人动过手脚。

4.4 Capabilities:细粒度权限控制

SUID 有个大问题:要么全有,要么全无。一个程序只要设了 SUID root,就能干任何事。这太粗暴了。Capabilities 机制就是为了解决这个问题——把 root 权限拆成一个个独立的能力。

# 查看进程的 Capabilities
$ getpcaps $$
Capabilities for '1234': = cap_chown,cap_dac_override,cap_fowner+ep

# 给二进制文件设置 Capabilities
$ setcap cap_net_bind_service=+ep /usr/bin/nginx

# 查看文件的 Capabilities
$ getcap /usr/bin/nginx
/usr/bin/nginx = cap_net_bind_service+ep

常用的 Capabilities 有哪些?我列几个最常见的:

Capability 作用 替代了什么
CAP_NET_BIND_SERVICE 绑定低端口(< 1024) 不需要 root 运行服务
CAP_DAC_OVERRIDE 绕过文件权限检查 部分文件读写权限
CAP_SYS_ADMIN 系统管理操作(挂载、命名空间等) 很多 root 操作
CAP_NET_RAW 使用原始套接字 ping、tcpdump 等
CAP_SETUID 允许改变 UID su、sudo 等

我的建议:容器场景下,尽量用 Capabilities 替代 SUID。比如 Nginx 要监听 80 端口,只需要 cap_net_bind_service,完全没必要给 root 权限。我在生产环境里,所有 Web 服务都只用 Capabilities,SUID 文件数量控制在个位数。

4.5 权限隔离实战:从设计到落地

光讲理论不行,我们来看一个实际场景。假设你要部署一个 Web 应用,包含 Nginx、PHP-FPM、MySQL 三个组件。怎么设计权限隔离?

# 1. 创建专用用户
$ useradd -r -s /sbin/nologin nginx
$ useradd -r -s /sbin/nologin php-fpm
$ useradd -r -s /sbin/nologin mysql

# 2. 设置文件所有权
$ chown -R nginx:nginx /var/www/html
$ chown -R mysql:mysql /var/lib/mysql
$ chown -R php-fpm:php-fpm /var/log/php-fpm

# 3. 严格控制权限
$ chmod 750 /var/www/html
$ chmod 700 /var/lib/mysql
$ chmod 640 /var/log/php-fpm/*.log

# 4. 给 Nginx 绑定低端口的能力
$ setcap cap_net_bind_service=+ep /usr/sbin/nginx

# 5. 移除不必要的 SUID
$ chmod u-s /usr/bin/passwd  # 如果不需要普通用户改密码

我曾经踩过的坑:有次部署 PHP 应用,把 session 目录设成了 777,结果被上传了 webshell。正确的做法是:session 目录所有者设为 php-fpm 用户,权限 700,Nginx 通过 Unix socket 通信,不直接读写 session 文件。

4.6 知识体系总览

下面这张图把 Linux 权限隔离的完整体系画出来了。从最底层的 UID/GID,到文件权限位,再到特殊位和 Capabilities,每一层都在解决特定的问题。

Linux 权限隔离体系结构图 Linux 权限隔离体系 第1层:用户与组(UID/GID) RUID / EUID / SUID | 主组 / 附加组 | 系统用户 vs 普通用户 作用:确定进程和文件的所有者身份 第2层:文件权限位(rwx) 所有者(u)| 所属组(g)| 其他人(o) 作用:控制对文件和目录的读、写、执行访问 第3层:特殊权限位(SUID/SGID/SBIT) SUID(4000)| SGID(2000)| SBIT(1000) 作用:临时提升权限 / 继承组 / 保护目录文件 第4层:Capabilities(细粒度权限) CAP_NET_BIND_SERVICE | CAP_DAC_OVERRIDE | CAP_SYS_ADMIN 作用:将 root 权限拆分为独立能力,最小化特权 每一层都在解决上一层的不足:身份 → 访问控制 → 临时提权 → 细粒度权限

4.7 权限审计与加固清单

最后,我分享一份我自己的权限审计清单。每次上线新系统,我都会按这个列表过一遍:

  1. 用户审计:检查是否存在无主文件(find / -nouser -o -nogroup)
  2. SUID/SGID 审计:列出所有特殊权限文件,确认每个都是必要的
  3. 权限最小化:服务账号的 home 目录权限不超过 750
  4. Capabilities 审计:检查二进制文件的 Capabilities 设置(getcap -r /)
  5. umask 设置:确保默认 umask 是 027 或更严格
  6. 日志审计:开启 auditd 监控关键文件的权限变更

总结一句话:权限隔离不是配一次就完事了。我每个月都会重新审视一遍权限策略,因为业务在变,攻击手法也在变。记住:最小权限原则不是口号,是每天都要做的事。