ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Linux UID和GID详解:从概念到实操,彻底搞懂用户权限体系

Linux UID和GID详解:从概念到实操,彻底搞懂用户权限体系 写这篇学习记录时我刚在云服务器上折腾完一批用户权限顺便把之前一直没彻底搞懂的几个基础概念重新过了一遍。UID和GID中文就是用户ID和组ID。如果你和我一样刚开始学Linux时对着ls -l输出里的“root root”发过呆或者好奇为什么不直接用用户名而是用一串数字来标识身份那这篇文章大概能帮你把这些疑问一次性理清楚。它适合所有刚接触Linux的初学者也适合那些已经在用Linux但总觉得基础不扎实、准备面试或者想深入理解权限体系的朋友。我会从概念、原理、实操到常见问题按我自己的学习路径来记录全程配上可以直接复制的命令和踩坑心得。这不是教科书式的罗列而是我经过实际测试、带着思考写下来的经验总结。1. UID和GID到底是什么先搞清概念再动手1.1 从文件的属主和属组说起第一次接触ls -l时我看到每行前面都有类似-rw-r--r--的权限串后面还跟着两个名字。比如drwxr-xr-x 2 root root 4096 Jan 15 10:30 testdir我当时有两个疑问这里显示的“root root”到底是什么第二个“root”是不是多余后来才明白第一个root是文件属主也就是文件的主人第二个root是文件属组决定了这个文件所属的组。而内核在真正判断权限时并不直接看“root”这个字符串而是看root这个用户名背后对应的数字标识——这就是UID用户ID和GID组ID。类比一下就很好懂UID和GID就像身份证号用户名和组名就像身份证上的名字。平时我们打交道时用名字更方便但真正办理业务、核对身份时系统认的还是那个唯一的编号。Linux里也是一样内核只认数字人名是给人类看的。1.2 /etc/passwd和/etc/group里的奥秘要理解UID和GID必须打开两个文件/etc/passwd和/etc/group。/etc/passwd里每一行代表一个用户典型的一行长这样zhangsan:x:1001:1001:张三:/home/zhangsan:/bin/bash用冒号分成7个字段我刚开始时总记不住顺序后来总结成一个口诀名字、密码占位、UID、GID、注释、家目录、登录Shell。第1个字段用户名比如zhangsan。第2个字段以前存密码哈希现在普遍放一个x占位真正密码挪到了/etc/shadow普通用户不可读。第3个字段UID用户的数字ID。第4个字段GID用户主组的数字ID。第5个字段注释信息一般填姓名或说明。第6个字段家目录路径。第7个字段登录Shell也就是用户登录后使用的解释器。再看/etc/group每一行代表一个组dev:x:1002:zhangsan,lisi,wangwu同样用冒号分隔组名、组密码占位符、GID、组成员列表。这里有个容易忽略的点一个用户创建时会被分配一个主组primary group同时还可以加入很多附加组supplementary group。文件权限判断时主组和附加组都会被检查但登录时的有效组通常是主组。这个细节在共享目录权限配置时特别关键后面实操部分会再提。2. 内核只认数字不认名字UID/GID为什么这么设计2.1 用户名的存在只是给人看的我一度觉得Linux这个设计很“反人类”明明有更直观的用户名为什么权限判断非要绕一层数字后来接触了网络和嵌入式相关的场景才明白数字ID在系统内部处理时效率高得多而且不会因为改名或不同机器上用户名不同而产生歧义。举例来说你在两台服务器上各有一个用户都叫test但一台上UID是1001另一台是2001。如果两台服务器通过NFS共享同一个目录那么第一台服务器上的test用户写的文件在第二台服务器上可能就变成另外一个用户的了。原因很简单NFS协议在传递文件属主信息时传的是UID/GID数字不是用户名。也就是说跨系统协同工作时真正一致的不是名字而是数字ID。这也是为什么有经验的管理员在搭建多机环境时会提前规划统一的UID/GID范围。2.2 从文件权限到进程身份UID如何生效权限判断的过程可以简单概括为当一个进程试图访问文件时内核用进程的身份ID和文件属主、属组的ID进行比对再根据比对结果决定应用哪一段rwx权限。在Linux里进程的身份比我们想得更复杂一点。一个运行中的进程至少有三种UID类型含义典型场景Real UID进程实际由哪个用户启动记录“发起者”是谁Effective UID进程当前以谁的权限运行决定真正拥有的权限Saved UID被保留的旧EUID以便程序在必要时切换回用于setuid程序的临时降权/恢复大多数普通进程的这三种UID是相同的但执行了带有setuid位的程序后会发生变化。最经典的例子是/usr/bin/passwd你看它的权限时注意看属主权限部分的sls -l /usr/bin/passwd -rwsr-xr-x 1 root root 59976 Feb 10 2023 /usr/bin/passwd普通用户执行passwd修改自己的密码时按道理只能访问/etc/shadow而这个文件是只有root能读写的。可实际上普通用户能正常改密码关键就在于passwd程序带了setuid位它会让进程的Effective UID临时变成root从而获得读取/etc/shadow的权限。这就是“程序权限替身”的机制理解它对排查权限问题非常有帮助。2.3 普通用户、系统用户和root的边界Linux里UID并不总是分配给真实用户有很大一片保留给系统服务。按照常见发行版的约定UID 0特权用户root拥有整个系统最高权限。UID 1~999系统保留账号供守护进程或服务使用。这类账号通常没有登录Shell也没有家目录比如bin、daemon、mysql等。UID 1000~60000普通用户用于日常登录和业务操作。不同发行版的具体范围略有差异但大方向一致。比如Debian系曾经的普通用户起点是1000而一些老系统可能从500开始。了解这个范围有助于你在创建用户时合理地手动指定UID避免和系统用户撞车。3. 实操环节查看、创建、修改一套带走3.1 查看用户的UID/GID排查权限问题时第一时间肯定是确认当前用户和文件属主。我最常用的查看命令是idid uid1000(test) gid1000(test) groups1000(test),4(adm),27(sudo)输出第一行显示当前用户的UID和主组GIDgroups部分显示所有附加组。如果只想看某个用户的直接后面跟用户名id root uid0(root) gid0(root) groups0(root)也可以用getent命令来查询用户数据库它在某些场景下比直接cat /etc/passwd更可靠因为它会用到NSS配置的完整用户来源本地文件、LDAP等。比如getent passwd test test:x:1000:1000::/home/test:/bin/bash想快速列出所有用户的UID和GID可以配合awk处理/etc/passwdawk -F: {print $1, $3, $4} /etc/passwd想看文件真实的数字属主用ls -n它会用数字UID/GID取代用户名显示或者用statls -n myfile.txt stat -c %u %g myfile.txt3.2 创建用户时如何规划UID和GID刚开始我创建用户特别随意后来发现不规范的用户名和ID会让权限管理变得很痛苦。推荐的做法是创建之前先规划好ID段比如业务用户统一从10000开始服务账号继续使用系统保留段下的自定义范围。创建用户的命令是useradd常用参数如下useradd -u 10001 -g dev -G docker,wheel -m -d /home/zhangsan -s /bin/bash zhangsan-u 10001手动指定UID。-g dev指定主组为dev组该组必须已存在。-G docker,wheel指定附加组多个组用逗号分隔。-m同时创建家目录。-d /home/zhangsan指定家目录路径。-s /bin/bash指定登录Shell。这里有个特别容易踩的坑不同发行版的useradd默认行为不一样。在CentOS/RHEL上useradd默认会创建家目录并生成对应的邮件目录但在Ubuntu/Debian上直接用useradd创建用户往往不会自动创建家目录也不会要求设置密码。很多新手在Ubuntu上创建用户后切过去发现连home目录都没有就是这个原因。如果是Ubuntu环境我更推荐用adduser这个友好交互命令它会引导你设置密码并创建家目录如果你坚持要用useradd记得带上-m参数。3.3 修改已有用户的UID/GID如果一个用户创建之后ID不合适可以用usermod修改。修改UIDusermod -u 10002 zhangsan修改主组usermod -g dev zhangsan添加附加组usermod -aG docker zhangsan注意这个-aG里的-a一定要带上它表示追加append如果不加用户会被移出原来的所有附加组只保留新指定的组。这个误操作我帮同事排查过一次他本来想把用户加到docker组结果用户直接被踢出了sudo组导致机器上没法执行sudo非常耽误事。修改UID有个风险要特别提醒usermod -u只修改了/etc/passwd里的UID记录不会自动修改这个用户原来拥有的文件属主。也就是说改ID之后用户家目录或业务目录里的文件还会显示成旧的数字ID。正确的操作顺序是先记录旧UID下有哪些文件修改后再用chown把它们统一改过来。批量改属主的命令可以这样写先找出所有属于旧UID的文件再执行chownfind /home/zhangsan -user 10001 -exec chown 10002:dev {} \;执行前先不加-exec只跑一遍find确认列出的文件都在预期范围内再执行真正的修改。尤其是服务器上有大量业务数据的场景这个习惯能避免改错目录权限。3.4 修改文件属主和属组日常用得最多的应该就是chown和chgrp这两个命令了。基础用法如下chown zhangsan /data/test.txt chown zhangsan:dev /data/test.txt chown :dev /data/test.txt第一种只改属主第二种同时改属主和属组第三种只改属组。实际修改目录时遇到目录里还有大量子文件加上-R递归执行chown -R zhangsan:dev /data/projectchgrp则专门用来改文件的属组等价于chown :组名chgrp -R dev /data/project有一点需要说明普通用户只能修改自己拥有文件的属主和属组吗不对实际上普通用户几乎不能更改文件的属主这个操作会直接拒绝因为把文件“送”给别人是一个高风险操作。只有root或sudo权限才能执行chown。所以当你在权限受限的目录里执行chown报错时先检查一下当前用户。4. 特殊UID与权限位很多人忽略的重要细节4.1 uid 0、nobody和系统保留账号uid 0是root可以理解为系统的“最高权限身份证”。无论用户名改成了什么只要UID是0它就拥有root级权限。所以安全加固时要特别检查是否有多余的UID 0账号awk -F: $3 0 {print $1, $3} /etc/passwd正常情况下这个命令只应该输出一行root 0。如果看到其他账号也对应UID 0说明系统很可能被留下了后门账号需要立即处理。另一个常见的特殊ID是nobody通常在/etc/passwd里对应UID 65534或65535GID同理。它代表“没有任何权限的普通用户”通常用于Nginx、某些容器进程等以低权限运行的服务。理解nobody的定位能帮你避免把服务账号直接配成root运行降低被攻击后的影响面。4.2 setuid、setgid和sticky bit讲到UID和GID就绕不开权限位上的三个特殊标志setuidsuid、setgidsgid和sticky bit。它们和普通rwx权限一起存储在权限位上平时显示在可执行位的x位置属主权限里出现ssetuid执行时进程EUID变成文件属主的UID。属组权限里出现ssetgid执行时进程EGID变成文件属组的GID同时如果对目录设置setgid目录内新建的文件会自动继承该目录的属组。其他用户权限里出现tsticky bit常见于/tmp这种共享目录只有文件属主或root可以删除自己的文件避免用户误删他人临时文件。用chmod可以给文件或目录设置这三个位chmod us /path/to/file # 设置setuid chmod gs /path/to/dir # 设置setgid chmod t /tmp/shared_dir # 设置sticky bit检查系统里有哪些setuid程序可以用find / -perm -4000 -type f 2/dev/null这个命令应该养成定期检查的习惯因为setuid位一旦配合程序漏洞很容易被利用来提权。如果发现某些非常规程序带suid位就要格外警惕。4.3 跨服务器时UID不一致的坑前面说过NFS的场景再举一个具体例子公司有两台服务器同一批开发者的账号在A机器上UID是1001在B机器上忘了统一变成了1002。当开发者把A机器上产生的文件传到B机器后B机器上所有者和属组显示不再是他的名字而是一串数字。更麻烦的是如果两边共享同一个存储权限判断会完全错乱本来有权限的目录突然没权限了。解决办法是提前规划要么在每台机器上建立相同UID/GID的账号要么使用集中认证方式比如LDAP要么在文件传输后统一重启一遍属主。没有绝对完美的方案但最基础的一点是在项目初始规划时就把UID/GID纳入一致性方案里。5. 新手常见问题与排查技巧实录5.1 用户删了文件却显示一串数字现象用ls -l查看文件时属主和属组变成了一串数字比如1001。原因很简单文件属主的UID在/etc/passwd里已经查不到对应的用户名了通常是因为用户被userdel删除但文件还在。解决办法是重新创建同一个UID的用户或者用chown把文件归属调整到现有用户chown test:test /path/to/file避免这个问题的最好习惯是删除用户之前先找出它名下的文件find / -user zhangsan -ls确认这些文件是否有保留价值再决定保留还是删除。我在一台测试机上删过一个业务账号结果漏掉了/var/log下的应用日志后续排查问题时看日志全是数字非常痛苦。5.2 新建用户没有家目录现象useradd test之后su - test进入用户环境发现当前目录是/而且/home/test不存在。原因通常是发行版默认行为不同或者创建命令里漏了-m参数也可能家目录被其他文件占用了。解决方法很简单mkdir -p /home/test chown test:test /home/test usermod -d /home/test test如果是Debian/Ubuntu系强烈建议直接用adduser交互式创建用户它会自动创建家目录、设置密码一次性处理好。5.3 修改UID后文件权限“失效”现象给用户执行了usermod -u 10002 zhangsan登录后发现自己的家目录进不去了或者文件权限全乱了。原因就是第3.3节提到的问题文件属主还是旧UID和用户新UID对不上权限判断自然失败。解决套路是find /home/zhangsan -user 10001 -exec chown 10002:10002 {} \;如果你修改的是业务目录记得也要扫描业务路径别只改家目录。另外提醒一句修改UID前最好通知相关同事避免在线服务正在写入文件时你改了属主导致服务瞬间没有写权限。5.4 常用排查命令速查我把自己平时用到的高频命令整理成了一个小表方便随时查阅需求命令查看当前用户ID信息id查看指定用户ID信息id username查看passwd文件全部用户cat /etc/passwd或getent passwd查看group文件全部组cat /etc/group或getent group查找UID为0的特殊账号awk -F: $30{print $1,$3} /etc/passwd查看文件数字属主ls -n或stat -c %u %g file修改文件属主/属组chown 用户:组 文件递归修改目录属主/属组chown -R 用户:组 目录检查系统setuid程序find / -perm -4000 -type f 2/dev/null这套命令配合/var/log/secure或/var/log/auth.log里的认证日志基本能覆盖绝大多数权限相关问题的排查。踩过几次坑之后我的体会是UID和GID这套体系虽然概念简单但真正理解它需要把“用户—组—文件—进程”这条链路串起来。很多权限问题看着复杂拆到最后无非就是以下三件套当前进程以什么身份在跑、目标文件的属主和属组是什么、文件的所属组和用户是否匹配访问规则。把这三个问题回答清楚权限相关的故障就解决了一大半。下一篇我打算接着写权限位的三位八进制数值和umask的计算逻辑如果你也在这个问题上卡过欢迎留言交流。
返回列表