ARTICLE DETAIL

资讯详情

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

Linux文件权限从入门到实战:chmod/chown与Permission denied排查

Linux文件权限从入门到实战:chmod/chown与Permission denied排查 很多人第一次在 Linux 上遇到权限问题都是从一行Permission denied开始的。我也一样当年刚接手一台服务器部署网站时 nginx 反复报错文件明明就在/var/www/html下面躺着盯着看了半天也不知道哪里不对折腾了一下午才搞明白问题出在我根本没看懂ls -l输出里那一长串字符的含义。从 Windows 转过来的朋友更容易在这个地方懵圈Windows 遇到权限问题是弹窗问你要不要给管理员权限Linux 不是它直接拒绝留给你一行冷冰冰的报错。而且印象里“权限不够就提升权限”的直觉在 Linux 里往往会把事情搞得更糟。今天这篇文章我打算把 Linux 文件的权限和拥有者这一套从底层逻辑讲到实操命令重点放在chmod、chown、chgrp以及那些一上手就会踩的坑。无论你是刚入门的新手还是被线上问题缠住的运维和开发应该都能从里面找到点有用的东西。1. 从一次Permission denied说起Linux权限体系的三张门卡在动手改权限之前先把模型搞清楚。Linux 对每个文件和目录都记录着三类人的权限属主owner、属组group、其他人others。你可以把这三类人想成三张门卡——一张卡是文件主人的一张卡是文件所属组的一张卡是路过所有人的。至于每个文件允许这三类人做什么由 9 个字符来记录。看一个最简单的例子。随便在某个目录下执行ls -l你会看到类似这样的输出-rw-r--r-- 1 root root 1234 Apr 12 10:00 myfile.txt drwxr-xr-x 2 root root 4096 Apr 12 10:00 mydir第一列的第一个字符表示文件类型-是普通文件d是目录l是软链接b和c是块设备和字符设备。后面 9 个字符分成三组每组三个分别对应属主、属组、其他人每组里依次是r读、w写、x执行。比如-rw-r--r--的意思是属主可读可写属组可读其他人可读。这里有个细节容易被忽略权限位缺失的位置必须用-占位不要想当然地跳过。很多人看-rwxr--r--时会数错位置以为属组也有执行权限其实就是没盯住那 9 个字符的排列顺序。在真正修改权限之前把ls -l的第一列逐位读出来是必须的基本功。接下来是判断顺序的问题。当一个进程要访问某个文件时内核不是“从上到下找符合的权限”而是先看进程的有效用户 IDeuid是否等于文件的属主是就用属主那三位权限不是再检查进程的属组是否落在文件属组里在就用属组那三位权限都不是才轮到“其他人”那三位。很多新人会犯一个典型错误以为自己是 root 用户组的成员就应该能读某个文件结果文件属于另一个组不匹配最后落到 others 位权限不够就报错。理解了这条判断顺序你才会明白改权限时到底应该动u位、g位还是o位。再补充一个反直觉的事实root 几乎不受文件权限位的约束。它能读能写任意文件不是因为文件给了它权限而是内核直接绕过了这层检查。所以你会看到文件权限是000普通用户进不去root 照样能改。这不是权限失效而是 root 天生就是“特权门卡”。正因如此日常操作尽量少用管理员身份去跑出了问题排查难度会成倍增加。想确认当前身份随时用id命令看 uid、gid 和附加组。提示排查权限问题前第一件事永远是用id确认自己是谁而不是急着看文件。身份搞错了后面全白费。2. chmod实战数字法与符号法的选型逻辑权限模型看懂了chmod才有意义。这个命令的作用是修改文件的权限位也就是那 9 个字符。它有数字法和符号法两套写法我几个场景混用了很久才慢慢摸清各自的适用边界。2.1 数字法4、2、1拼出来的权限值数字法的核心是把三种权限翻译成数值再相加r4、w2、x1。为什么偏偏是这三个数因为三种权限的组合总共有 0 到 7 八种情况正好对应八进制的一位。也就是说7 421表示可读可写可执行5 41表示可读可执行6 42表示可读可写。每组三位数字从左到右分别代表属主、属组、其他人。所以chmod 754 file的含义是属主拥有全部权限7属组可读可执行5其他人只读4。具体数值和对应关系可以看这张表数字权限位含义常见用途7rwx读 写 执行脚本、目录6rw-读 写普通文档5r-x读 执行程序、目录4r--只读只读文档0---无权限敏感文件这里有一条经验文件不要随便给执行位除非它真的是脚本或程序目录则通常至少给5也就是可读可执行否则别人连目录都进不去。很多刚入门的朋友给目录设成644结果发现目录只能看到列表却进不去本质就是少了x位。2.2 符号法精确修改某一位数字法的缺点是我只想给文件加一个执行权限还得先心算当前值是多少。这时符号法更方便语法是“对象 操作符 权限”三段式。对象有u属主、g属组、o其他人、a所有人操作符有添加、-移除、设置为权限就是r、w、x。chmod ux script.sh # 给属主加执行权限 chmod g-w file.txt # 去掉属组的写权限 chmod or file.txt # 把其他人的权限设为只读 chmod arx appdir # 所有三类人都加上读和执行符号法的优势在交互式操作时特别明显不用算数值改完立马ls -l验证。而且它的操作是“增量式”的只影响你指定的那一位不会像数字法那样要求你一次性写全整个 9 位误操作的概率低不少。2.3 脚本用数字、手调用符号我自己习惯的做法是写部署脚本、自动化配置时用数字法因为数值是确定性的同一个命令在任意环境跑出来结果完全一致方便记录和排错交互式排查问题时用符号法因为不用心算也减少误改其他位的概率。两种方法最终改的都是同一个权限矩阵没有孰优孰劣只有场景适配之分。比如在 Ansible 这类配置管理工具里一律写数字法别人看代码时一眼就能知道目标状态是什么。2.4 -R 递归别乱用chmod -R非常方便也最容易出事。假设你执行chmod -R 777 /data/整个目录树下的所有文件、目录、子目录全变成 777任何人能读能写能执行这在生产环境几乎是灾难。更稳的做法是分开处理先找出所有目录统一给755再找出所有普通文件统一给644。命令可以这样写find /data -type d -exec chmod 755 {} \; find /data -type f -exec chmod 644 {} \;如果时间紧非要一条chmod -R那也要在跑之前确认目录下没有私钥、没有配置文件、没有临时目录。我见过太多线上事故是“顺手一个-R 777”导致的真的不要抱侥幸心理。3. chown与chgrp改拥有者之前先想清楚两件事chmod改的是“权限矩阵”chown改的是“这张文件归谁”。权限设置得再漂亮如果文件的属主不是运行服务的那个用户依然会报Permission denied。所以chown在运维里的出场率一点都不比chmod低。3.1 基本语法和常见组合chown alice file.txt # 把文件属主改成 alice chown alice:devops file.txt # 同时修改属主和属组 chown :devops file.txt # 只改属组属主不动 chgrp devops file.txt # 等价于 chown :devops注意alice:devops中间是冒号不是点号。老版本 Linux 可能兼容点号写法但新环境建议统一用冒号避免在脚本里出现解析问题。如果只想改目录本身不想动里面的内容就别加-R如果确实要递归改整个目录树再考虑用-R。3.2 什么时候必须改拥有人实际场景里chown用得最多的是这么几类从压缩包解压出来的文件属主往往是你本机用户但服务器上运行服务的用户是www或nginx就得执行chown -R www:www /var/www/html把整个站点目录交给服务账户。挂载外部磁盘后文件属主显示为某个 uid 数字比如 1000 或 1001而服务器上的服务账户是另一个 uid需要按实际 uid 重新归属。团队协作时把项目目录的属组改成共享组大家在同一个组里读写就不用互相chmod 777了。一个常见问题是文件属主改成谁我一般遵循“谁运行谁拥有”的原则。文件由 nginx 进程读写就归 nginx 用户由某个业务账户读写就归那个账户。别只看自己当前登录的用户名要把“运行时身份”和“管理时身份”分开。3.3 递归修改的边界意识chown -R和chmod -R一样递归操作一定要先确认边界。我给自己定的规矩是执行前先pwd确认当前路径然后写完整路径再想一下“这个目录下的所有内容我都确定要改吗”。尤其是绝对不要让chown -R碰到/usr、/etc这类系统目录。系统文件的所有者一旦被改乱服务起不来、用户登录不上排查起来极其痛苦。真不小心改了系统目录也别慌优先检查哪些目录的属主不对用发行版自带的包管理器重新校验并恢复文件属性比如 rpm 系的rpm -Vadeb 系的dpkg --verify能少走很多弯路。4. 目录权限是另一套玩法为什么755的目录能进、644的进不去文件权限和目录权限看着是同一套rwx语义却完全不同。很多人把文件的权限思维直接套到目录上结果就是各种各样“明明给了权限却还是不行”的怪问题。4.1 目录上的读写执行分别是啥意思权限位文件上的含义目录上的含义r读取文件内容列出目录内容能看到文件名w修改文件内容在目录中创建、删除、重命名条目x执行文件进入目录、访问目录内的文件关键在x。目录没有x权限即使你拥有r权限也只能看到文件列表无法cd进去也无法访问目录内任何文件。所以目录通常至少是5r-x能看能进但没有写权限大家只读不写。常见的目录权限是755属主可写其他人都只能读和执行。如果你想建立一个只允许属主进入的目录那就是700。4.2 删文件不看文件权限看目录权限这是一个非常容易被忽略的盲区删除一个文件系统检查的是你对该文件所在目录是否有写权限而不是文件本身的权限。也就是说在一个大家都可写的目录里只要你对目录有w权限就能删掉别人的文件哪怕那个文件自己是000。反过来也成立一个文件是777但你没有它所在目录的写权限你删不掉它最多只能修改文件内容如果你对它本人有写权限的话。这个理解在实际运维里极其重要。比如用户反映“我对某文件有写权限但保存失败”先去检查它所在目录权限问题经常在目录那一层。因为这个特性公共可写目录必须配合粘滞位使用。/tmp就是一个典型例子它的权限是drwxrwxrwt最后一位t就是粘滞位后面我会详细讲。没有粘滞位的公共可写目录等于大家可以互相删文件乱套是迟早的事。5. SUID、SGID、Sticky Bit容易被忽略的三个特殊权限位前面的9位权限是基础但 Linux 文件权限里还有三个特殊权限位平时不起眼关键时刻很有用也容易埋雷。它们分别是 SUID、SGID 和 Sticky Bit。5.1 SUID为什么普通用户可以改自己的密码看passwd命令的权限-rwsr-xr-x 1 root root 68208 ...注意属主那组权限多了一个s这就是 SUIDSet User ID。它的含义是当普通用户执行这个程序时进程的有效用户 ID 临时变成 root而不是执行者本人。这样一来普通用户才能去修改/etc/shadow里自己的密码条目因为那个文件只有 root 能写。SUID 不是玩具。如果某个程序被设置了 SUID又存在可利用的漏洞攻击者等于拿到了一把 root 权限的钥匙。生产环境里定期用find / -xdev -type f -perm -4000 -ls检查系统中有哪些 SUID 文件是必要的安全巡检项。设置 SUID 用chmod us file或数字法chmod 4755 file。5.2 SGID让同组的人生成的文件自动属于组SGID 也有类似机制文件上设置 SGID 会让进程临时获得文件属组的权限。但更常用的场景是在目录上设置 SGID在设置了 SGID 的目录下新建的文件默认属组会继承目录的属组而不是创建者的默认组。这对团队协作非常友好大家往同一个共享目录里放文件自动归到同一个组不用每次都手动chgrp。设置方式是chmod gs dir用ls -l看显示为drwxrwsr-x。注意那个s的位置在属组权限的x位上大写S表示没有执行权限时的 SGID小写s表示有执行权限时的 SGID别混淆了。5.3 Sticky Bit/tmp 目录为什么不乱套再看/tmp的权限drwxrwxrwt 20 root root 4096 ...最后一位t就是粘滞位Sticky Bit。它的作用是在这个目录下除了 root只有文件的属主或目录属主能删除或重命名文件其他人即使有目录写权限也动不了你的文件。换句话说/tmp是公共可写目录但因为有粘滞位A 用户不能删 B 用户的临时文件。设置方式是chmod ot dir显示为drwxrwxrwt。公共可写目录强烈建议加上粘滞位不加就是裸奔。5.4 特殊权限位的数值写法三个特殊权限位也可以用数字表示在传统三位八进制前面多加一位4表示 SUID2表示 SGID1表示 Sticky。例如chmod 4755、chmod 2770、chmod 1777。不过如果是在交互环境里操作我更推荐用符号法因为数字法写错一个 bit 很难一眼看出来读起来也不直观。无论用哪种设置完一定要ls -l确认结果。6. 权限报错排查链路从报错信息到定位根因的完整思路线上遇到Permission denied时最怕的就是瞎试。一会儿chmod 777一会儿chown自己试完了问题还在时间也浪费了。我一般按下面的顺序走定位快很多。6.1 排查的九个步骤先确认当前身份id看 uid、gid 和附加组。看目标对象的真实权限ls -l或stat目标文件。逐层检查路径上每一级目录的执行权限。检查目录是否有写权限针对删除、新建操作报错。用namei -l /完整/路径一次看清每一级路径的权限和属主。看挂载选项mount或findmnt关注ro、noexec、nosuid、nodev。考虑 ACLgetfacl看是否有setfacl设置的额外规则。看 SELinuxgetenforce如果是 Enforcing还要考虑安全上下文问题。看日志journalctl、dmesg、应用自身日志常有明确提示。很多朋友步骤 1 和 2 都不做直接跳到第 4 步甚至第 7 步这样很容易南辕北辙。我也是踩过几次坑之后才养成“先查身份、再看权限”的习惯。6.2 一次典型排障案例某次同事反馈Nginx 站点下有个上传目录一直报 permission denied。我先id看了一眼 Nginx 的 worker 进程用户是nginx再ls -l看上传目录权限是755属主是root。问题线索已经很清晰755目录属主 rootworker 进程用 nginx 身份不在属主位也不在属组位属于“其他人”“其他人”只有r-x没有w所以上传写文件失败。定位后执行chown nginx:nginx upload_dir问题解决。整个过程花了不到一分钟因为每一步都有明确的验证手段。我见过不少同事在这个场景里直接chmod 777也能解决问题但代价是所有人都能往里面塞文件安全隐患极大。能精准定位就不要用“权限全开”这种粗暴手段。6.3 几个让人多花时间的误区第一以为 root 报错都是“权限太大”才报错。实际上 root 报错多半是文件系统只读或 SELinux 拦截跟权限位无关这时候查mount和getenforce才是正路。第二忽略了粘滞位。某些公共目录明明该删的文件删不掉先怀疑粘滞位而不是怀疑权限不够。第三双眼只盯着文件本身忘了检查父目录。路径上任何一级目录缺少x都会卡死后面的所有访问。这些误区我全都踩过每次都是回到上面的排查链路才把问题找出来。7. 权限规划指南别等出问题再去救火权限和拥有者管理的本质是“谁应该碰这个文件”的决策。与其每次等报错再去救不如一开始就把规则想清楚。7.1 umask 决定新文件的默认权限新建文件和目录的默认权限由umask决定。默认设置一般是022对应“文件644、目录755”意思是新建的东西默认不给组和其他人写权限。如果你希望新文件默认对组可写可以把umask改成002那新建的文件就是664、目录是775。团队协作时统一umask是有价值的规范否则不同成员各自的umask不一致就会出现“他创建的文件我只能读”这种琐碎问题。7.2 最小权限原则的常用搭配场景推荐权限原因普通配置文件644属主可写其他只读脚本文件755属主可写可执行其他可读可执行私钥文件600 或 400绝不能给组和其他任何权限共享目录775 或 2770组内协作杜绝其他人写入公共读目录755属主可写其他人只读私钥这类敏感文件我通常直接600组内也不给读宁可授权麻烦一点也别留后门。共享目录如果希望新建文件自动继承组就在775基础上加 SGID也就是2770效果会更好。7.3 周期性巡检习惯最后提一个小习惯隔一段时间跑一条find命令把可疑的高危权限文件列出来看看有没有新增的777文件或 SUID 文件。find / -xdev -type f -perm -0002 -ls 2/dev/null # 全用户可写的普通文件 find / -xdev -type f -perm -4000 -ls 2/dev/null # SUID 文件这种巡检不需要每天做但可以在每周运维清单里加一条。权限问题最怕的不是复杂度而是临时改完忘记还原。一个777的文件在那里挂一个月没人知道它是什么时候出现的但风险一直在。最后分享一点个人体会。我在实际使用中的习惯是每个项目建一个专用用户和一个专用组文件默认归属这个组不同角色按实际需要给不同权限。看起来是前期多花了几分钟但后面省下的是无数个深夜排查。建议你拿到一台新机器先在虚拟机里把chmod、chown、namei、stat挨个跑一遍跑熟了再上真实环境遇到报错心态会稳很多。
返回列表