☰
Linux权限管理实战:从chmod到sudo,厘清文件权限与安全配置
2026/10/17 4:18:47 网站建设 项目流程

1. “问题不大,权限不够”:从一次登录失败说起

有段时间我养成了一个坏习惯——在公司内部某台共享服务器上,图省事把所有要修改的文件都chmod 777。后来一次例行安全扫描,发现某目录下多了一个不属于任何人的可执行文件,被标记为“危险操作来源”。排查之后我才意识到,权限不等于摆设,Linux 下的一切安全问题,归根结底都是权限问题。组里一个新人接手环境时,连自己的用户目录都进不去,因为他把.config目录的权限写得乱七八糟,把自己锁在了外面。

那会儿我才认认真真把 Linux 权限相关的指令从头过了一遍。这篇文章就是基于那段“交学费”的经验写的,不搞教科书式的通篇铺陈,只讲我在实际服务器上每天都会碰到的几条命令,以及它们背后容易被人忽略的细节。无论你是刚开始摸服务器的小白,还是已经被权限问题折磨过的老手,这几条指令都值得重新对照一遍。

2. 权限模型:别急着敲命令,先搞懂“谁”和“能做什么”

2.1 三类主体和三种权限位

Linux 的权限模型可以用一句话概括:系统对“用户/用户组/其他人”这三种主体,分别赋予“读/写/执行”三种操作能力。在命令行里输入ls -l,能看到类似-rw-r--r--的输出,这串字符就是权限的“压缩密码”。

从左往右拆:

  • 第 1 位是文件类型(-普通文件,d目录,l软链接);
  • 第 2-4 位是属主(u,user)权限;
  • 第 5-7 位是属组(g,group)权限;
  • 第 8-10 位是其他人(o,other)权限;
  • 后面跟的数字代表硬链接数,再后面是属主、属组、大小、修改时间和文件名。

权限本身也是三位一组:r代表读(4 分)、w代表写(2 分)、x代表执行(1 分)。为什么很多人直接写755、644?因为八进制数字就是把每组的三个 rwx 换成数值相加。例如rwxr-xr-x,属主是 4+2+1=7,属组是 4+0+1=5,其他也是 5,于是简写为755。

这里有一个容易踩的坑:目录的 r、w、x 和文件的含义不完全一样。对目录来说:

  • r只能让你“看到”目录里有哪些文件名;
  • w允许你在目录里新建、删除、重命名文件;
  • x才是真正允许你“进入”这个目录,并访问其中文件的能力。

所以一个目录如果只有r没有x,用ls能看到文件名,但cd进去会提示权限不够,访问其中任何文件也会失败。反过来只有x没有r,你能进去,但看不到有哪些文件,只能凭完整路径访问已知文件。给目录设置权限时,通常建议r和x成对出现,否则极易出现“看得到进不去”或者“进得去看不到”的诡异现象。

2.2 ls 输出里的隐藏线索

除了这十个字符,ls -l还会暴露一些容易被忽略的线索:如果权限位后面跟着一个.,表示该文件启用了 SELinux 上下文;如果跟着+,表示该文件上设置了扩展 ACL 规则(后面会讲到);如果属主或属组显示为一个数字而不是名字,说明系统里找不到对应的用户记录,通常是残留文件或者容器场景下常见。

实操时我一般会在ls -l基础上加-h,把文件大小变成人类可读的 K/M/G 格式,加--time-style=long-iso,让时间输出成2025-06-12 18:30:01这种标准格式,日志排查时按时间排序特别好用。ls -ld则用来查看目录自身权限,而不是目录里面的内容,检查 /tmp、/var/log 这类“不友好目录”时很关键。

提示:ll在很多发行版里是ls -l的别名,但某些精简环境里没有定义,养成直接敲ls -l的习惯,到哪都不会抓瞎。

2.3 为什么要用“组”而不是直接给每个人授权

权限设计里最常用到的其实是“组”。一台服务器上可能有开发、运维、数据分析三个角色,如果给每个人单独分配权限,管理成本会指数级上升。正确做法是:把某类需要相同权限的人放进同一个组,然后针对“组”设置权限,之后人员变动只需要把用户加进/移出组,文件的权限位完全不用动。这是多数团队服务器的标准做法,也是应对审计需要的基础设计。

3. 修改文件权限:chmod、chown 与 chgrp 的完整实操

3.1 chmod 的两种模式:字母模式和数字模式

chmod是用来改权限位的主命令,写法有两种流派:符号模式(字母)和数字模式(八进制)。两者没有绝对优劣,但混用时容易出错,建议团队内部统一风格。

符号模式适合精确调整某一位。比如:

  • chmod u+x file.sh:给属主加执行权限;
  • chmod g-w file.txt:去掉属组的写权限;
  • chmod o=r file.txt:把其他人的权限“设置”为只读(注意是等号,不是加减号);
  • chmod a+r file.txt:所有人(all)都加上读权限。

数字模式则适合直接“覆盖设定”,例如chmod 644 file.txt表示属主可读写,其他人只读;chmod 755 script.sh表示属主可读写执行,其他人和属组仅可读执行。最常见的几个组合建议直接背下来:

  • 644:普通文件,属主读写,别人只读,配置文件常用;
  • 755:可执行文件/目录,属主全权,其他人可读可进入;
  • 700:私有文件/目录,只有属主能进能改;
  • 600:敏感文件,比如私钥、凭据,只有属主能读写;
  • 4755或4754:带 setuid 的特殊组合,下文会细讲。

新手最容易犯的第一个错误,是对目录递归用了chmod -R 777。-R的意思是递归,会把目录下所有文件和子目录全部改一遍。看似一劳永逸,实际上把“是否需要执行权限”这种本该由文件性质决定的事情一刀切了。更稳妥的做法是分两步:先用find /path -type f -exec chmod 644 {} \;给普通文件设权限,再用find /path -type d -exec chmod 755 {} \;给目录设权限。这样目录保留了 x 权限(可进入),普通文件不会被误加执行位。

3.2 chown 与 chgrp:改属主和属组的边界

chown用于修改文件的属主和属组。常见写法:

  • chown alice file.txt:仅改属主;
  • chown alice:devs file.txt:同时改属主为 alice、属组为 devs;
  • chown :devs file.txt:只改属组,前面的属主用冒号占位;
  • chown -R alice:devs /data/project:递归修改整个目录树。

chgrp则是单独修改属组的命令,虽然chown :devs file.txt也能达到同样效果,但老派运维习惯用chgrp,因为可读性更好,也避免手滑把属主改错。

这里必须提醒一条原则:chown只有 root 能执行。普通用户不能把自己的文件“送”给别人,也不能把别人的文件“抢”过来,这是系统防越权的基本设计。如果你遇到“Operation not permitted”提示,先确认自己有没有sudo权限,而不是反复试命令。

3.3 实操场景:部署一套 Web 服务的权限规划

举个例子,我要在一台新服务器上部署一个静态站点,站点根目录在/var/www/html,Web 进程以www-data用户运行。合理的权限规划流程是:

  1. 创建组webteam,把负责维护的管理员账号加入该组;
  2. 把网站目录属主设为www-data,属组设为webteam;
  3. 目录权限设为750:属主(web 进程)可读写进入,组内成员可读进入,其他人都被拒之门外;
  4. 文件权限设为640:属主可读写,组内成员可读,其他人无权限;
  5. 唯一可能需要写的目录,比如上传目录uploads/,单独设为www-data:webteam且权限770,保证只有进程和组内成员能写。

整个过程中用到的是chown -R www-data:webteam /var/www/html,再配合chmod逐个目录设置。这个做法比chmod -R 777复杂一些,但避免了网站被任意系统用户篡改的风险,排查问题的时候也能一眼看出哪个目录权限不合理。

注意:chown修改完属主属组后,建议立刻用ls -l复查一遍,因为有些发行版会自动把属主的组改为用户主组(例如用户 alice 的主组是 alice,则chown alice file会把属组一并改成 alice),这就很容易导致原本期望的“组内共享”变成“只有单人能访问”。

4. 用户与组管理:权限分配的下层基础

4.1 用户管理指令:useradd 与 usermod

权限的主体是用户。日常维护中,useradd、usermod、userdel这三条命令值得一提。

useradd创建用户时,参数极其重要,因为不同发行版对新用户的默认设置不一样。我常用的完整写法是:

useradd -m -s /bin/bash -G devs,wheel -c "某开发者" alice
  • -m:创建用户主目录(不加的话可能没有/home/alice目录,许多新人因此踩坑);
  • -s:指定 shell,如果设置成/bin/bash,就按 bash 环境处理;
  • -G:附加组,用户会加入这些次要组(注意:和主组不是一回事);
  • -c:备注信息,一般写姓名或用途,方便后续识别。

usermod是在用户创建之后修改信息的。最常见的操作是追加组:usermod -aG devs alice。这里必须强调-a(append)几乎要作为固定搭档使用。如果不加-a,-G会把用户从其他所有附加组里移除,相当于重置了用户的所有附加组权限。我见过有人想给某同事临时加一个 docker 组,结果顺手把人家从十几个项目组里全踢出来了,第二天十几个项目同时报“权限不足”。

删除用户的命令是userdel -r alice,-r会连带删除用户主目录和邮件池。如果用户的主目录下有重要业务数据,务必确认备份后再执行;没有-r时用户删除了,但主目录还在,有时会留下孤儿目录(属主和属组都显示为数字),后续清理很麻烦。

4.2 组管理:groupadd 与 gpasswd

组操作相对简单:

groupadd devs gpasswd -a alice devs # 把用户加入组 gpasswd -d alice devs # 从组中移除

gpasswd比直接改/etc/group文件安全,因为后者如果编辑中途格式错误,可能导致整个系统登录异常。组修改还有一个容易被忽略的规则:用户加入新组之后,必须重新登录(或重新开启一个会话)才会生效,因为登录时获得的组列表不会动态刷新。如果你看到明明加进了 docker 组,执行 docker 命令还是提示权限不足,先执行id或者groups看输出里有没有 docker,没有就是会话没刷新,重新登录即可。

4.3 passwd 与密码策略的简单维护

passwd也是权限相关指令里不可跳过的一条。普通用户运行passwd只能改自己的密码;root 运行passwd alice可以强制重设别人的密码,也可以直接锁定/解锁账户(-l/-u)。针对弱密码账户,建议在团队里约定:密码至少 12 位,包含大小写、数字和符号,并定期轮换。虽然passwd不能直接强制用户改密码,但 root 可以用chage -d 0 alice强制用户下次登录时立刻改密码,这在临时创建临时账号时很实用。

5. 特殊权限位与访问控制扩展:从 777 的误区里跳出来

5.1 setuid、setgid 与粘滞位:隐藏在常规权限之外的三种特殊权限

普通权限位之外,Linux 还提供三套“特殊权限”,对应的数值分别是 4(setuid)、2(setgid)、1(粘滞位,sticky bit)。它们平时不显眼,但一旦用错,就是安全漏洞的温床。

  • setuid(权限位表现为属主的 x 变成 s 或 S):命令以属主而不是执行者的身份运行。经典例子是/usr/bin/passwd,它的属主是 root,普通用户执行它时能临时获得 root 权限去修改/etc/shadow文件,但又不直接把 root 交给用户。这个设计很精妙,但自定义脚本设置 setuid 极其危险,因为如果脚本本身有漏洞,等于是把 root 的钥匙挂在门口。
  • setgid(属组 x 变成 s 或 S):文件执行时以属组身份运行;如果设置在目录上,则该目录下新建的文件和子目录,默认继承目录的属组,而不是创建者自己的主组。这一点非常适合团队共享目录——在共享目录上执行chmod g+s /data/shared后,无论谁往里面放文件,文件属组都是项目组,不会因为创建者属于不同用户组而导致其他成员无法访问。
  • 粘滞位(目录权限最后一位的 x 变成 t 或 T):最常见于/tmp目录。设置了粘滞位的目录里,所有人都能创建文件,但只有文件属主(或 root)才能删除别人的文件。这样避免了“公共垃圾桶里互相扔东西”的问题。

设置方法:

chmod u+s /path/to/file chmod g+s /path/to/dir chmod +t /path/to/dir

或数字模式:

chmod 4755 /path/to/file chmod 2770 /path/to/dir chmod 1777 /tmp

注意数字模式下特殊权限位放在普通权限位之前(四位数字),比如4755表示 setuid + 755,1777表示粘滞位 + 777,2770表示 setgid + 770。检查时用ls -l看 x 位是否被 s/t 替代,如果显示大写 S 或 T,说明特殊权限位没生效或者该位本身没有执行权限,这实际上是一个异常状态,需要排查。

5.2 扩展 ACL:比 chmod 更细粒度的“定向授权”

有些场景下,chmod 的三种主体(属主、属组、其他人)不够用。比如同一份文档目录里,alice 需要读写权限,bob 只需要读权限,其他人一律不可访问。用 chmod 去表达这种“组内差异”就很吃力,这时候就该上 ACL(Access Control List)。

setfacl和getfacl是核心工具。常见用法:

setfacl -m u:alice:rw /data/project # 给用户 alice 单独授读写权限 setfacl -m g:devs:rx /data/project # 给组 devs 授读执行权限 setfacl -x u:alice /data/project # 移除用户 alice 的自定义规则 setfacl -b /data/project # 移除所有扩展 ACL 规则

设置后执行getfacl /data/project,输出里会多出一行user:alice:rw-之类的记录,也就是说,原来ls -l权限位之外,还有一份更细粒度的授权清单存在。这也是之前提到ls -l显示+号的原因。

5.3 umask:新文件与目录的“出厂默认权限”

项目里经常遇到“为什么新建的文件是 644,我却想要 660”的问题,这背后是umask在起作用。umask不是修改权限位的命令,而是决定“默认减去哪些权限”的掩码。

默认权限的完整算法是:文件的最大权限是 666,目录的最大权限是 777,实际默认权限 = 最大值减去 umask 值。如果 umask 是022,那么新建文件为666 - 022 = 644,新建目录为777 - 022 = 755。如果 umask 是077,文件变600,目录变700。

查看当前值:umask。临时修改:umask 027。如果想永久修改,写入/etc/profile或用户的~/.bashrc。团队协作时,建议安全基线用077或027,这样默认情况下其他组用户看不到你的文件,避免“手滑把敏感数据暴露全组”。别小看这一步,很多“权限事故”都是 022 或更宽松的 umask 把不该暴露的文件放出去了。

6. sudo 权限管理:给“管理员权限”装一道闸门

6.1 为什么不用 su,而是用 sudo

很多新手习惯用su切到 root 干活。但服务器多人协同时,共享 root 密码既无法追踪操作者身份,又容易在交接时泄露。sudo的设计思路完全不同:用户用自己的账号和密码提权,执行记录留存在日志里,并且可以精确限制“谁在哪些主机上,以哪个用户身份,执行哪些命令”。

sudo的配置在/etc/sudoers文件里,修改时必须用visudo命令,因为它会先做语法检查,防止你把 sudoers 改坏导致所有提权全线崩溃。我见过有人直接vim /etc/sudoers改坏后,连sudo都执行不了,只能找宿主机团队介入修复,非常狼狈。

6.2 sudoers 规则的三层结构

一条 sudo 规则的基本格式是:

用户/组 主机 = (身份) 命令

实际拆解:

  • alice ALL=(ALL) ALL:alice 可以在所有主机上以任意身份执行任意命令,这是“完全管理员”配置,授予时要非常谨慎;
  • %devs ALL=(ALL) ALL:devs 组所有成员拥有同等级权限;
  • bob ALL=(ALL) NOPASSWD: /usr/bin/systemctl:bob 执行 systemctl 时不用输密码;
  • carl ALL=(ALL) /usr/bin/systemctl restart nginx, /usr/bin/systemctl status nginx:carl 只能执行指定的两个 systemctl 动作,不能执行 start、stop、reload 等其他子命令。

这里有一个细节:sudo 的命令匹配是“前缀匹配”,不是“命令名匹配”。如果规则写/bin/systemctl restart nginx,用户实际执行/bin/systemctl restart nginx --extra-arg可能也会命中。更安全的做法是加上sudoers配合COMMAND后面的""或者直接限制参数,但这不是新手阶段必须掌握的,记住一条:规则写得越具体越安全。

用sudo -l可以查看当前用户被授权执行的所有命令列表。每次给成员开 sudo 权限前,先执行sudo -l复查一遍,能有效避免“多给”的情况。

6.3 用日志反查操作者

配置好 sudo 之后,日志默认记录在/var/log/auth.log(Debian 系)或/var/log/secure(RHEL 系)。当用户通过 sudo 执行命令时,日志里会记下时间、用户、主机、原用户、执行命令等字段。排查“是谁改了系统文件”时,这几乎是唯一的线索。所以我每次布置服务器任务时,都会提醒成员:优先使用 sudo 而不是 su,即使你是唯一管理员,日志也是未来排查的救命稻草。

7. 常见问题与排查技巧实录

7.1 遇到 Permission denied,先检查哪几层

很多新手一看到Permission denied就慌,其实排查顺序是有迹可循的:

  1. 用ls -l看文件属主和属组是否对得上;
  2. 用id看当前用户实际所在的组;
  3. 检查目录路径上每一级目录的 x 权限(中间某一个目录没有执行权限,整个路径都会被拦断);
  4. 用getfacl看是否有扩展 ACL 覆盖了 chmod 设置;
  5. 检查是否设置了 setgid/粘滞位,特别在共享目录时这影响删除和新建行为;
  6. 如果是挂载盘,检查挂载选项里是否带noexec(会禁止任何文件执行)、nosuid(忽略 setuid 位)等。

我之前排查过一个开发环境的问题:用户明确有/home/data/work目录的权限,但访问文件时一直提示权限不足。后来namei -l /home/data/work/report.txt一查,发现/home/data这层目录权限是700,属主是 root,普通用户根本进不去。这个namei命令能按路径逐级检查每一层的权限,比手动一层层ls -l高效得多,值得记进你的工具箱。

7.2 目录删不掉文件,八成是粘滞位或目录权限问题

“我是 root,为什么删不了普通用户目录下的文件?”答案往往不在文件本身,而在目录。如果所在目录没有写权限,或者设置了粘滞位,只有文件属主或 root 才能删除。千万不要用chmod -R 777去突破,正确做法是:先确认为什么不允许删除,再决定是否把目录权限设置改为770、2770之类,或者用setfacl精确授权。公共目录里我习惯保留粘滞位,以保证临时文件的清理权留在创建者手里,避免误删他人数据。

7.3 脚本明明有了 x 权限,执行却说 Permission denied

这种情况优先看脚本开头有没有有效且正确的解释器路径(例如#!/bin/bash写在第一行),其次是检查ls -l里是否呈现出-rw-------这种 600 情形下的可执行文件,第三是看挂载选项,比如/tmp可能默认noexec,你在 /tmp 下写脚本,给了 755 也跑不起来。遇到这种问题,最简单的验证方法是把脚本挪到/home/user/bin下,再执行一次;能运行说明是挂载选项的问题,不能运行则继续排查。

7.4 sudo 时提示不在 sudoers 文件中

这属于极其常见的一次性错误:自行将普通用户加入了wheel组,但新开的会话尚未生效,或者该发行版的 sudo 仅认可sudo组而非wheel组。解锁方式也很简单:切换到 root 账户(如果你知道 root 密码),执行visudo,增加%wheel ALL=(ALL) ALL或把用户加入正确组,然后重新登录测试。这条经验特别适合刚接手陌生服务器的时候,因为你永远不知道前任管理员用的是哪种组名。

7.5 权限设置“看起来对”但行为不符合预期

这类问题的隐蔽性很强,往往是扩展 ACL 或特殊权限位在作怪。比如某文件明明 644,但某用户就是能编辑,用getfacl一看,多出一行user:alice:rw-,罪魁祸首在这里。再比如目录禁止其他用户写,但里面某个子目录却设置了 setfacl,里面的文件可以被人任意删除。建议在排查权限问题时,把ls -l、getfacl、namei -l、mount | grep noexec四条命令的执行结果拼在一起看,百分之九十的问题都能露出真面目。

ls -l /path/to/file getfacl /path/to/file namei -l /path/to/file mount | grep ' /path'

8. 常用权限指令速查表与选择建议

为了方便日常翻阅,我把平时用到的权限指令简单归纳成一张表,你可以直接保存下来:

指令作用常用示例
chmod修改文件/目录普通权限位chmod 750 /data
chown修改文件属主与属组chown -R alice:devs /data
chgrp仅修改文件属组chgrp devs /data/file
umask设置新文件/目录默认权限掩码umask 027
setfacl设置扩展 ACL 的细粒度权限setfacl -m u:alice:rw /data
getfacl查看扩展 ACL 规则getfacl /data
useradd创建用户useradd -m -s /bin/bash alice
usermod修改用户信息/附加组usermod -aG devs alice
gpasswd管理用户组成员gpasswd -a alice devs
passwd修改用户密码/锁定账户passwd alice
sudo按授权规则临时提权sudo systemctl restart nginx
visudo安全编辑 sudoers 配置visudo -f /etc/sudoers
namei逐层解析路径权限namei -l /var/www/html/index.html

使用建议就三条:

  • 写权限比读权限重要得多。失去读权限最多是看不见,失去写权限则意味着无法修改文件内容;但更危险的是对目录的写权限,因为它同时决定你能不能在目录里新建或删除文件。给进程或团队成员分配目录权限时,能不给写就不给写。
  • 给目录授权时,用“组”+“ACL”组合,而不是直接给单个用户逐条加规则。组规则维护成本低,ACL 适合处理少数例外,两者配合既灵活又不至于让权限表变成一锅粥。
  • 所有生产环境的权限变更,先记录目标状态,再执行指令,最后用ls -l/getfacl验证。如果变更环节出错,至少还能通过历史记录很快回退,而不是靠记忆去猜。

9. 我自己踩过之后才明白的三件事

写到最后,聊几个实际操作中的体会。

第一,千万不要迷信chmod 777。很多“临时能跑”的方案,最后都会变成生产环境里的长期方案。特别是共享目录和上传目录,777 等于把删除、篡改文件的权限交给了服务器上任意一个用户,一旦系统里存在其他漏洞,这条权限通道会让损失成倍扩大。换个思路:权限不够就把访问者加入正确的组,再通过 ACL 做例外,多花的两分钟远比事后紧急修复来得省心。

第二,“属主”和“属组”永远先于权限位被确认。权限位再宽松,如果属主/属组本身就对应着错误的人或组,后面怎么调整都是白费力。每次拿到一台陌生服务器,我习惯先ls -lidh看看几个关键目录的归属,再cat /etc/group看有哪些重点组,几秒钟就能摸清这套环境的权限设计思路。

第三,给重要脚本或者关键目录写权限变更时,先复制一份再操作。听起来很基础,但真遇到chown -R手滑把系统目录的属主改错了,即便你能切换 root 重新找回,恢复文件组归属也是极其头疼的过程。备份永远是权限操作里最便宜的保险。

Linux 的权限指令并不多,但每条指令背后都对应着一套安全设计逻辑。把基础打扎实,再遇到“权限不足”的报错,你就不会再病急乱投医,而是顺着主体、权限位、目录层级、特殊位、ACL、日志这条线索,一查一个准。

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

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

立即咨询