< 返回

    Linux 用户、权限与身份管理详解

    2026-02-04 20:50 作者:技术部 阅读量:9

    Linux 的安全模型建立在身份(Identity)所有权(Ownership)访问控制(Access Control) 三者紧密耦合的基础上。这一模型从 Unix 时代延续至今,并在现代内核中不断被细化与分层,形成了经典 DAC(自主访问控制)+ 现代 MAC(强制访问控制)+ 能力机制(Capabilities)+ 命名空间(Namespaces)+ 资源控制(cgroups)的复合体系。

    1. 身份标识的核心:UID 与 GID 的语义

    每个进程在内核眼中只有两个数字:真实 UID(ruid)有效 UID(euid)保存 UID(suid) 以及对应的 GID 集合。

    • ruid(真实用户 ID):启动进程的实际用户,通常不变
    • euid(有效用户 ID):内核在权限检查时真正使用的身份
    • suid(保存的 set-user-ID):用于在 execve 后恢复权限,常与 setuid 位配合

    经典例子:/usr/bin/passwd 程序文件拥有 setuid 位且 owner 为 root。

    执行流程:

    1. 用户 wu(UID 1000)执行 passwd
    2. 内核看到文件有 setuid 位 → 把进程的 euid 设置为文件拥有者(0)
    3. 进程以 root 有效身份运行,得以修改 /etc/shadow
    4. 但 ruid 仍为 1000(内核知道这是谁发起的)

    这种“临时提升权限”的机制是 setuid/setgid 程序存在的根本原因,但也成为历史上最常见的安全漏洞来源之一。

    现代内核引入 capabilities 来取代大部分 setuid root 程序,将 root 的全能权限拆分为约 40 种细粒度能力(如 cap_net_bind_service、cap_sys_ptrace、cap_dac_override 等)。

    2. 文件系统访问控制决策流程(VFS 层)

    当进程尝试 open/read/write/exec 一个文件时,内核 VFS 层执行的完整决策顺序(简化版):

    1. 检查文件系统是否挂载了 noexec、nosuid、nodev 等标志
    2. 检查 SELinux / AppArmor / Landlock 等 LSM(Linux Security Module)钩子
    3. 如果通过,则进入经典 DAC 检查:
      • 进程 euid == 文件 uid → 匹配 owner 权限位
      • 进程任一 gid ∈ 文件 gid 或进程补充组 → 匹配 group 权限位
      • 否则匹配 other 权限位
    4. 如果任何一步拒绝 → 返回 EACCES(Permission denied)

    关键点:目录的 x 权限决定能否“进入”并解析路径中的后续组件。即使文件本身有读权限,如果上级目录没有 x,也无法访问。

    3. 特殊权限位的内核实现语义

    • setuid(S_ISUID):execve 时若文件有此位,则新进程 euid = 文件 uid(而非调用者 ruid)
    • setgid(S_ISGID):
      • 文件:execve 时 euid = 文件 gid(极少用)
      • 目录:新建文件/子目录时,继承父目录的 gid 而非创建者的主 gid
    • sticky bit(S_ISVTX):仅对目录有效,限制删除权——只有文件拥有者、目录拥有者或 root 能删除目录中的文件(/tmp 的经典用法)

    这些位存储在 inode 的 i_mode 高 12 位中,与普通 rwx 位并列。

    4. umask 与文件模式创建掩码

    新建文件/目录时的初始模式由以下公式决定:

    text
     
    文件默认模式 = 0666 & ~umask
    目录默认模式 = 0777 & ~umask
     
     

    常见 umask 值与结果:

     
     
    umask 文件模式 目录模式 典型场景
    0022 0644 0755 标准单用户服务器
    0002 0664 0775 组内协作开发(组可写)
    0027 0640 0750 严格服务器(其他用户无权限)
    0077 0600 0700 最高隔离(仅拥有者可见)
     

    umask 影响的是“允许”的权限,而非“强制”的权限。最终还受文件系统默认 ACL 或继承规则影响。

    5. Capabilities 的分层设计思想

    Linux 内核从 2.6.24 开始引入 capabilities,将传统 root(capable() 全为 true)拆分为独立的可授予能力。

    每个进程拥有一个 capability 集合(inheritable、permitted、effective、bounding、ambient 五组)。

    最重要三组:

    • permitted:进程可能使用的能力上限
    • effective:当前真正生效的能力
    • inheritable:可被子进程继承的能力

    典型场景:让非 root 进程绑定低端口

    text
     
    文件能力:cap_net_bind_service=+ep
    → execve 后 permitted 与 effective 都获得此能力
    → 进程无需以 root 身份启动即可 listen 80/443
     
     

    6. 现代身份隔离:User Namespace 的革命性变化

    User namespace 允许进程在自己的“用户视图”中把 UID 0 映射到宿主机的非特权 UID。

    容器典型映射:

    • 容器内 root(UID 0) → 宿主机某个高位 UID(如 100000)
    • 容器内普通用户 1000 → 宿主机 101000

    这导致了根本性的权限隔离:容器内看似 root 的进程,在宿主机上只是普通用户,无法直接影响其他 namespace 或真实 root。

    结合 mount/pid/net/uts/cgroup/time 等 namespace,形成完整的容器隔离基础。

    7. 服务器运维中最常遇到的权限模型误区与正确心法

    误区 1:认为 777 就能“解决问题” → 实际暴露了所有用户可写权限,极易被恶意进程利用

    误区 2:把服务跑在 root 下“最保险” → 一旦被突破,攻击面无限大;应尽量用专用系统用户 + capabilities

    误区 3:忽略目录的 x 位 → 文件有 644 但上级目录只有 rx→,导致“Permission denied”

    正确心法顺序:

    1. 确定进程运行身份(ps -eo user,pid,cmd | grep 服务名)
    2. 确定目标资源拥有者与权限(ls -lZ /path)
    3. 判断是否需要调整 chown / chmod / setcap
    4. 验证 LSM 上下文(-Z 选项)与 capabilities(getcap)
    5. 最后看日志与 audit(/var/log/audit/audit.log 或 journalctl)

    结语

    Linux 权限体系的本质是“一切决策基于身份与规则的匹配”,而非“谁运行谁最大”。从经典的三组九位权限,到 capabilities 的细粒度拆分,再到 namespace 的身份隔离,每一层都在试图把“过度授权”的窗口越缩越小。

    真正掌握这一体系的关键不在于记住所有命令,而在于养成提问习惯:

    • 这个进程的有效身份是什么?
    • 目标资源的拥有权与权限三角匹配了吗?
    • 是否有额外的 LSM 或 capability 限制?
    • 如果隔离失败,攻击者能获得多大权限提升?

     

    建立这种思考路径后,无论面对传统服务器、容器环境还是未来的 eBPF + Landlock 加固场景,你都能快速定位问题根源。

    联系我们
    返回顶部