☰
Linux用户权限全解析:从UID到sudo的安全实践指南
2026/10/10 3:29:55 网站建设 项目流程

玩Linux这些年,被问得最多的就是“Linux用户权限”,尤其是一批刚接手服务器的运维同事,一上来就习惯性切到root,最后权限崩了都不知道怎么排查。其实用户权限这个事,说难不难,但真要吃透,得从底层的用户模型、文件权限位、sudo授权再到故障排查串起来看。这篇文章我就按自己实际管理服务器的经验,从零把整条链路捋一遍,既能给刚入门的朋友当教程,也能让有经验的同行当作排查手册参考。

1. 先搞懂Linux是怎么看待“用户”的

1.1 UID/GID:你喊他老王,系统只认数字

Linux系统里出现的每个用户,本质上都不是一个“名字”,而是一个数字。这个数字就是UID(用户ID),对应的组也有GID(组ID)。你在终端里看到root、zhangsan这类名字,那只是给人看的“翻译”,系统内核在判断文件属主、进程权限时,用的全是UID和GID。

讲个我自己踩过的坑:有一次我从旧服务器打包了一个网站目录,解压到新机器后发现文件属主显示503而不是某个用户名。原因就是压缩包里记录的UID是503,而新机器上没有对应UID的用户,系统就干脆直接显示数字了。所以理解UID/GID,对后续排查文件属主错乱、数据迁移这类问题非常有帮助。

查看一个用户的完整身份信息,用id命令就够:

id zhangsan # 输出类似:uid=1001(zhangsan) gid=1001(zhangsan) groups=1001(zhangsan),10(wheel)

1.2 三类用户角色:管理员、系统服务、普通用户

Linux用户大致可以分成三类,它们的UID范围和用途完全不同:

用户类型UID范围典型账号主要用途
超级用户0root系统的最高权限,能做任何操作
系统用户1-999(CentOS/RHEL)bin、daemon、nobody、www-data运行系统服务,一般不能登录
普通用户1000及以上zhangsan、devops日常登录、跑业务、开发调试

这里要特别提醒一下:很多人以为系统用户没用,其实它们是“安全设计”的一部分。比如Nginx默认就是用一个低权限用户去跑worker进程,而不是直接用root。这样即使Web应用被攻破,攻击者拿到的也只是低权限shell,没法直接控制系统。所以创建服务账号时,尽量给一个独立系统用户,而不是把所有服务都塞在root下跑。

1.3 四个配置文件:权限体系的“户口本”

用户和组的信息并不是存在某个数据库里,而是散落在四个纯文本配置文件中。理解这些文件,你才能真正看懂useradd、usermod这些命令背后的动作。

  • /etc/passwd:用户基本信息,包含用户名、UID、GID、家目录、登录shell等。
  • /etc/shadow:用户密码加密后的哈希值,以及密码策略(有效期、修改间隔等)。
  • /etc/group:组基本信息,包含组名、GID、组内成员。
  • /etc/gshadow:组密码和组管理员信息,日常用得比较少。

拿/etc/passwd里的一行举例:

zhangsan:x:1001:1001::/home/zhangsan:/bin/bash

字段依次是:用户名、密码占位符、UID、GID、备注、家目录、登录shell。注意这个x不是密码本身,加密后的密码都在/etc/shadow里,这也是为什么普通用户读取不了shadow文件的原因。

提示:几乎不要手动去编辑这四个文件,就算要改,首选vipw和vigr命令,它们会帮你做文件锁和语法检查。我就是早期图省事直接vim编辑,结果字段写错了,搞得某用户登录直接被拒,排查半天。

2. 用户的创建、管理与删除:别只会useradd

2.1 创建用户这一步,参数远比你想的重要

创建一个用户看似简单,就一句useradd zhangsan,但如果只敲这一句,你会发现新用户连家目录都没有。因为不同发行版对useradd的默认行为不一样,有些默认创建家目录,有些不创建。所以我在生产环境里一般会写成这样:

useradd -m -u 1050 -s /bin/bash -g dev -G docker,svn zhangsan

参数解释:

  • -m:创建家目录。
  • -u:指定UID,方便统一管理,避免迁移时属主错乱。
  • -s:指定登录shell,一般给/bin/bash;如果只是跑服务,可以设成/sbin/nologin禁止登录。
  • -g:指定主组。
  • -G:指定附加组,可以有多个,用逗号隔开。

创建完用户后还要记得设初始密码:

passwd zhangsan

如果你在写自动化脚本,不想交互式输密码,可以用:

echo "Initial@123" | passwd --stdin zhangsan

但生产环境不建议这种方法,密码会留在shell历史里,安全隐患很大。

2.2 修改用户和密码策略:usermod、passwd、chage

用户建好后不是一劳永逸的,改权限、改组、锁定账号都会用到usermod。我常用这几个场景:

# 把zhangsan加入docker组(注意是 -aG,不是 -G) usermod -aG docker zhangsan # 锁定账号,禁止登录 usermod -L zhangsan # 解锁账号 usermod -U zhangsan # 设置账号过期时间,常用于临时账号 usermod -e 2025-12-31 zhangsan

这里有个血泪教训:-G和-aG看起来差不多,但实际效果天差地别。usermod -G docker zhangsan会把zhangsan从原来的附加组中全部移除,只保留docker一个组。我就见过同事这样操作后,用户直接失去了wheel组的sudo权限,然后一脸懵地找我问为什么不能sudo了。所以,想添加附加组、保留原有组时,务必用-aG。

密码策略方面,用chage管理:

# 查看密码策略 chage -l zhangsan # 强制90天后必须改密码,提前7天提醒 chage -M 90 -W 7 zhangsan

2.3 删除用户和清理残留:userdel的常见坑

删除用户也有讲究。userdel zhangsan只删用户本身,不删家目录和邮件,所以我在清理员工离职账号时会用:

userdel -r zhangsan

-r会连家目录和mail spool一起删掉。但要注意,这个命令不会删除该用户在其他地方遗留的、属主为该用户的文件。如果你不确定,建议先查找再处理:

find / -user zhangsan -ls 2>/dev/null

还有另一种情况:用户已经删了,但系统里留下了大量UID未知的文件。这种文件看着很碍眼,处理办法一般是找出来重新chown给现有用户,或者直接删除。这里也提醒大家,在大批量删除用户前,先把它们的文件备份或转移,不然数据丢了真没法交代。

3. 文件权限:rwx背后的完整逻辑

3.1 权限位、数字和目录的特殊性

Linux每个文件和目录都有三组权限,分别对应属主(u)、属组(g)和其他人(o)。每组权限用rwx表示,翻译成数字就是r=4、w=2、x=1。

举个例子,chmod 755 script.sh的含义是:

  • 属主:7 = rwx,可读可写可执行。
  • 属组:5 = r-x,可读可执行,不可写。
  • 其他人:5 = r-x,可读可执行,不可写。

这个规则大家基本都懂,但目录权限和文件权限的理解容易出偏差。文件的话,r是能看内容,w是能改内容,x是能执行。目录则完全不同:

  • r:能列出目录里的文件名。
  • w:能在目录里创建、删除、改名文件。
  • x:能进入目录,也就是cd进去的基础权限。

这意味着就算你对某个目录拥有写权限,如果没有执行权限,你也进不去目录,更不可能在里面删除文件。常见场景就是给Web项目目录配置权限时,只给755而忘了x,结果其他用户能列目录却进不去,404一片。

3.2 属主属组调整:chmod、chown、chgrp的正确用法

实战中改权限和属主是最高频的操作。我常用这几个组合:

# 数字方式,一次设置三组权限 chmod 750 /data/project # 符号方式,只给属组加写权限 chmod g+w /data/project # 递归修改目录及内部文件 chmod -R 755 /data/project # 同时修改属主和属组 chown devops:dev /data/project # 只改属主 chown devops /data/project # 只改属组 chgrp dev /data/project

这里我要强烈反对一个操作:chmod -R 777。很多人权限不对就直接丢777,等于把文件权限全放开了。一次两次看起来没事,但一旦服务器上有其他低权限进程被利用,777目录里的敏感数据就可能被拖走。正确做法是,先想清楚谁需要读、谁需要写、谁需要执行,然后给最小权限。

另外,使用chown时有几个细节容易踩坑:

  • chown dev:dev表示属主和属组都改成dev用户和dev组。
  • chown :dev只改属组不改属主。
  • 递归操作-R一定要确认路径没问题再执行。我就有同事把chown -R的路径写错,直接把整个根目录的属主改成普通用户,系统差点起不来。

3.3 SUID、SGID、Sticky Bit:三个容易被忽略的特殊权限

除了基础的rwx,Linux还有三个特殊权限位,日常排查权限问题和安全加固时经常遇到。

SUID(Set User ID):当一个可执行文件设置了SUID,那么任何用户运行它时,进程的属主会变成文件属主,而不是运行者。最典型的例子是/usr/bin/passwd,它的权限是-rwsr-xr-x,这个s就代表SUID。普通用户执行passwd时,能以root身份修改/etc/shadow中的密码,然后进程结束后权限又恢复普通用户。

SGID(Set Group ID):文件上有SGID时,运行进程的属组会变成文件属组;目录上有SGID时,在该目录新建的文件会自动继承目录的属组。这条在协作目录里特别有用:

chown :dev /data/team-project chmod 2770 /data/team-project # 2 就代表 SGID

这样只要成员属于dev组,在这个目录里创建的文件,组身份都会自动是dev,不会因为谁创建的文件就归谁私有,省去一堆互相chgrp的麻烦。

Sticky Bit(粘滞位):最常见的场景是/tmp目录,权限是drwxrwxrwt,最后的t就是粘滞位。它的作用是:在设置了粘滞位的目录中,用户只能删除自己拥有的文件,即使目录的写权限让所有人都能创建文件,也不能乱删别人的。临时目录如果没这个位,就会出现用户A删掉用户B文件的情况。

查看特殊权限可以用ls -l,但特殊权限在数字上也有表示:SUID=4、SGID=2、Sticky=1。所以:

  • chmod 4777 file:设置SUID。
  • chmod 2770 dir:设置SGID。
  • chmod 1777 /tmp:设置粘滞位。

从安全角度讲,SUID是提权类问题的重点关注对象。运维日常巡检时,我会定期扫一遍系统里所有SUID文件:

find / -perm -4000 -type f 2>/dev/null

如果发现莫名其妙多出的SUID文件,尤其是有x权限的可执行文件,大概率有问题,重点排查。这类文件一旦被利用,普通用户可能获得root权限,是管理员最容易忽视的隐患。

4. sudo与授权管理:把root“借”出去的正确姿势

4.1 用visudo做最小授权,安全又省心

很多团队的坏习惯是把root密码给所有开发,一人一个root,出了问题根本不知道是谁干的。正确做法是用sudo做细粒度授权,把部分命令的权限下放给普通用户。

修改sudo配置务必使用visudo:

visudo

不要直接vim编辑/etc/sudoers,因为visudo会做语法检查。一旦写错,sudo可能直接瘫痪,到时候修起来更麻烦。

sudo配置行的基本格式是:

用户 主机=(角色) 命令

几个常见写法:

# 让zhangsan能执行所有命令,但仍需要输入自己的密码 zhangsan ALL=(ALL) ALL # 让dev组的成员无需密码就能重启nginx %dev ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart nginx # 只允许zhangsan以root身份运行useradd和usermod zhangsan ALL=(root) /usr/sbin/useradd, /usr/sbin/usermod

我个人在配置sudo时的原则是:能不给的权限坚决不给,能限制范围的尽量限制范围。比如开发人员需要查看系统日志,我就只授权tail和grep的某些日志路径;需要重启服务,就只授权对应的systemctl restart xxx。这样才能在方便和安全之间找到平衡。

这里还要注意NOPASSWD别乱用。虽然免密很爽,但你机器上任何一个普通账号被入侵,就等于直接给了对方root权限。我一般只在自动化脚本和CI/CD专用的账号上设置NOPASSWD,人用账号都要求输密码。

4.2 实战:为SVN服务创建独立用户并精细授权

结合“svn用户权限”这个常见场景,我来完整演示一个案例。假设我们需要为SVN版本库创建专用系统用户,并让运维同事能通过sudo来管理SVN服务,但又不能让他们拿到root。

第一步,创建专用系统账号,禁止登录:

useradd -r -s /sbin/nologin svn

-r表示创建系统用户,-s /sbin/nologin保证它不能登录shell。

第二步,创建SVN仓库目录并设置属主属组:

mkdir -p /data/svn/repos chown -R svn:svn /data/svn chmod -R 750 /data/svn

这样普通用户无法直接访问仓库目录,避免了代码被误删或泄露。

第三步,在visudo中给运维同事授权SVN管理命令:

ops ALL=(root) /usr/bin/svnadmin, /usr/bin/svnlook, /usr/bin/systemctl restart svnserve

这样运维只能执行和SVN相关的管理命令,不能随便改系统配置。

第四步,用sudo执行管理操作:

sudo -u svn /usr/bin/svnadmin create /data/svn/repos/newproject sudo svnlook tree /data/svn/repos/newproject

提示:这个方案的核心思路就是“一个服务一个账号,一组管理一条命令通道”。不管SVN还是Git、Jenkins,我都建议用独立账号跑,配合sudo做命令白名单。这样哪怕某个服务的账号被攻破,影响范围也限定在对应目录内,不至于拖垮整个服务器。

5. 权限问题排查与安全加固

5.1 我整理的高频故障清单

多年运维下来,权限相关的故障来来去去就那么几个类型。我把高频的整理成了一张速查表:

故障现象常见原因排查命令解决思路
Permission denied文件属主/属组不对,或缺少x权限ls -l、namei -l 路径修正属主属组或权限位
sudo: command not foundPATH环境变量没包含对应目录echo $PATH、which sudo修复用户PATH,尤其检查anaconda等自装软件的家目录路径
文件属主显示为数字原用户已删除,UID无归属find / -uid 1005 -ls将文件chown给现有用户,或重建相同UID的用户
新创建文件权限不对umask设置不合理umask修改全局或用户的umask
无法删除目录里的文件目录缺少w和x权限,或触发了Sticky Bit保护ls -ld 目录检查目录权限,确认粘滞位是否在起作用
切换用户后命令行提示符不对用户shell配置缺失或家目录权限异常ls -l /home/用户检查家目录属主是否为该用户,配置文件是否完整

这里特别说下sudo: command not found,这锅经常不是sudo的,而且用户的PATH变量里没有命令所在目录。比如我用anaconda装过Python环境,有些用户环境变量配置在~/.bashrc里,但通过sudo执行时,secure_path会覆盖PATH,导致sudo下找不到python或conda。解决办法是在visudo里调整secure_path,或者直接用sudo /usr/bin/python3这类全路径方式调用。这不是权限本身的问题,但非常常见,排查时报错信息又很混淆,容易让人误判。

5.2 权限审计与日常加固建议

权限安全不是一次配置完就高枕无忧的,要定期做一下几件事:

  1. 检查是否存在空密码用户
awk -F: '($2==""){print $1}' /etc/shadow

有输出就说明有用户密码为空,必须立刻设密码或锁定。

  1. 检查UID为0的用户

UID为0等同于root权限,正常系统里只能有root一个:

awk -F: '($3==0){print $1}' /etc/passwd

如果多出来别的用户,基本可以断定有异常。

  1. 检查sudoers配置
grep -v '^#' /etc/sudoers | grep -v '^$'

重点看有没有给普通用户配了不必要的ALL权限。

  1. 检查SUID文件变化

建议第一次先扫描建立基线,之后定期比对:

find / -perm -4000 -type f 2>/dev/null
  1. 检查用户家目录权限

用户家目录如果是777,别人就能随意看代码、删配置:

ls -ld /home/*

正常家目录权限应该是700或755,不要放开到777。

我在实际运维中还养成了一个习惯:权限变更前先记录原始属主和权限,用小脚本或者ls -l快照都行。一旦变更后出现问题,可以快速回滚。批量操作时也先拿一两个目录试点,确认无误再铺开。别嫌麻烦,权限这东西,出问题往往是连锁反应,一次大意就是一次事故。

最后分享一点个人体会

权限管理这件事,表面上是命令和参数的问题,本质上是对系统安全的敬畏。用户权限这个坑,我自己也踩过不少,最痛的一次是批量chown写错路径,差点把生产环境搞瘫。从那以后,凡是涉及权限变动的操作,我都强制自己先备份后操作,绝不裸奔。希望看完这篇文章的朋友,哪怕记不住命令,也一定要记住“最小权限”这四个字。平时多留意配置文件、多跑几次审计命令,服务器真的会少很多意外。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询