ARTICLE DETAIL

资讯详情

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

Linux文件权限完全指南:rwx、数字权限、chmod与排障

Linux文件权限完全指南:rwx、数字权限、chmod与排障 第一次在终端里敲下ll看到满屏的-rwxrwxr--时大部分人的反应都是愣住。电影里黑客敲键盘的画面看了不少真到自己上手 Linux却发现光看懂这一串字符就够喝一壶。作为一个运维干了十来年、帮同事修过无数次权限问题的老油条我可以很负责任地说文件权限这套东西是 Linux 新手到老手之间最重要的一道分水岭。搞清楚rwxrwxr--到底在表达什么你就能明白为什么同在一个目录下的文件有人能改有人不能改也能自己动手解决大部分Permission denied问题。这篇内容适合所有刚接触 Linux 的开发者、运维初学者也适合那些想系统补一遍权限知识、把模糊概念彻底捋清楚的半熟手。1. 拆开 rwxrwxr--这串字符的每一格都在说什么1.1 第一位是文件类型不是权限很多教程直接把-rwxrwxr--说成十个权限位这话不严谨。第一个字符其实不是权限而是文件类型。权限位真正只有后面九位前面这一位负责告诉你这到底是个什么东西。常见的文件类型有这么几种-普通文件比如文本、日志、二进制程序d目录directory这是你执行ls -l时见得最多的一种l符号链接symbolic link也就是软链接c字符设备文件比如/dev/ttyb块设备文件比如/dev/sdas套接字文件socketp命名管道FIFO这就是为什么你会看到drwxr-xr-x这样的目录、-rw-r--r--这样的普通文件。同样一段rwxrwxr--前面是d还是-含义完全不同。这里有个很实际的坑符号链接lrwxrwxrwx看起来是谁都能读写执行但你实际访问一个软链接时系统真正用的是它指向的目标文件的权限。软链接本身的权限基本是个摆设所以千万不要以为lrwxrwxrwx就代表这个文件可以随便改。1.2 后九位三组权限的三权分立真正的权限部分是后九个字符rwxrwxr--。这九位被分成三组每组三个字符顺序永远是r读、w写、x执行如果用不到对应的权限就用-占位。三组分别代表三类访问者第一组rwx文件属主uuser的权限第二组rwx文件属组ggroup的权限第三组r--其他所有人oother的权限举个例子一个脚本权限是-rwxr-xr--意思是文件属主可以读、写、执行同组的成员可以读和执行但不能修改其他无关用户只能读连执行都不行。理解这三组之后很多权限纠纷就说得通了。你明明能打开某个文件另一个同事却打不开很可能就是因为他不在文件所属的组里被其他用户这一档挡在了门外。1.3 单独看每个字符r、w、x 对普通文件意味着什么对普通文件而言三个权限位的含义是这样的r可以读取文件内容。比如cat、less、head、tail这些命令都需要文件有读权限。w可以修改文件内容。注意这里说的是改内容能不能删除这个文件取决于文件所在目录的权限跟文件本身的写权限没有直接关系。这个点后面目录权限部分会重点展开。x可以把文件当作程序或脚本来执行。对普通文本文件来说没有x权限你就只能看不能运行它。有一个细节经常被忽略一个脚本文件比如.sh要直接执行必须有r和x两个权限。因为内核实际是靠/bin/bash来解释执行脚本的bash 需要读文件内容所以只有x没有r的脚本直接./xxx.sh会报错。而二进制程序理论上只需要x但实际运行过程中动态链接库的加载、调试信息的读取等也经常需要读权限所以生产环境里二进制程序通常都是r-x一起给。2. 数字权限 774 是怎么算出来的八进制背后的编码逻辑2.1 r4、w2、x1这就是个二进制开关rwxrwxr--对应的数字权限是774。这个换算几乎是所有 Linux 面试必考题背后原理其实是一个 3 位的二进制开关。r对应数值 4w对应数值 2x对应数值 1。把每组的三个数值相加就是这个组的权限数字rwx 4 2 1 7rw- 4 2 0 6r-x 4 0 1 5r-- 4 0 0 4--- 0所以rwxrwxr--拆开就是 7属主、7属组、4其他连起来就是 774。为什么偏偏是 4、2、1而不是 1、2、3因为这三个值对应的是三个独立 bit4 是二进制 1002 是 0101 是 001。任意组合加起来都不会有歧义比如 6 只可能是 42代表rw-不可能是其他拆分。这正是八进制权限设计的精妙之处——紧凑、可逆、够直观。2.2 常见权限组合速查用了几百次权限之后我对下面这些组合已经形成了肌肉记忆新手朋友可以先收藏这张表数字字符表示含义0---无任何权限1--x仅可执行2-w-仅可写3-wx可写、可执行4r--只读5r-x可读、可执行6rw-可读、可写7rwx全部权限平时最常用的两组组合文件一般是644属主可读写其他人只读可执行文件和目录一般是755属主全部权限其他人可读可执行不能写。这两个是我配置服务器时的默认起点大多数场景都能用。2.3 umask 与新建文件的出厂默认权限你有没有好奇过为什么touch新建出来的文件默认是644而不是666因为系统里有个叫umask的权限遮罩负责给新建文件做减法。新建文件的基准权限是666因为新文件不该默认带上执行位新建目录的基准权限是777。umask 的值会从基准权限里扣掉对应的权限位。绝大多数发行版默认 umask 是022于是新建文件666去掉组写020和其他写002得到644新建目录777去掉组写和其他写得到755在终端里执行umask就能看到当前值umask 0027可以临时修改。我个人在多人协作的服务器上通常会建议把 umask 设为027这样新建文件默认就是640组内成员可读不可写其他用户什么权限都没有。这能省下很多同事创建的目录我能乱改吗这类麻烦。3. 目录权限才是真正的坑为什么 r-x 的目录进不去3.1 目录的 r、w、x 和文件的 r、w、x 不是一回事很多人把文件的权限概念直接套到目录上这是权限问题里最大的误区。目录本质上是一张文件名到 inode 的映射表所以它的三个权限位含义完全不同r可以列出目录里的文件名也就是ls能看到目录里有什么w可以在目录里新建、删除、重命名文件前提是还要有xx可以穿过目录也就是cd进入目录以及访问目录内文件的元数据打个比方目录就像小区门口的访客登记表。有r权限你能看到表上有谁有x权限你才能走进小区有w权限你才能往表上添加或划掉名字。三者缺了哪一个行为都完全不同。3.2 只有 r 没有 x能看到文件名却读不了详情我见过不少新手被这个组合折磨到怀疑人生。假设一个目录权限是r--你会发现ls能看到文件名列表因为读权限生效了但ls -l会报错因为要拿到每个文件的 inode 详细元数据系统必须沿着路径访问目录这需要x权限cd进不去cat目录里的文件报Permission denied反过来只有x没有r的目录也很有意思你能cd进去也能访问你知道确切文件名的文件但ls列不出任何东西。这种只放行已知文件的场景在一些接口服务目录里偶尔会用到。所以排查Permission denied时不能只看最终目标文件的权限还要看它所在的每一级目录。路径中任何一个目录缺了x你都到不了目标。3.3 删除文件看目录权限不看文件权限这是权限排障里最常见的认知错位。很多人以为文件删不掉是因为文件没有写权限大错特错。rm一个文件本质是在它所在的目录里删除这个登记条目。所以决定你能不能删掉它的是所在目录的写和执行权限而不是文件本身的权限。一个文件权限是444只读只要它所在目录是rwx你照样能把它删掉。反过来文件自己是666但目录权限是r-x没有写权限你也删不掉它系统报Operation not permitted。这个机制设计其实很合理文件内容归文件自己管但文件在不在这个目录里归目录管。3.4 生产环境目录权限的建议配置基于上面这些逻辑我在生产环境里常用的目录权限方案是这样的用户主目录700或750避免别人翻看你的个人配置Web 静态目录755属主可写其他人只读加可进入上传目录750属主为运行用户比如www-data不要无脑777团队共享目录2775开了 SGID后面第 5 节会详细解释这里特别想强调看到Permission denied不要第一反应就是chmod 777。777 等于把门全部拆掉很多时候问题反而会被掩盖给以后埋雷。4. 动手改权限chmod 和 chown 的实操方法与避坑经验4.1 数字法的完整实操改权限最常用的命令就是chmod。数字法的写法很直白chmod 774 backup.sh # 属主与组可读写执行其他人只读 chmod 644 README.md # 属主可读写其他人只读 chmod -R 755 /opt/app # 递归修改目录下所有文件和子目录递归参数-R看起来很省事用的时候一定要小心。一个典型的失误是在整个 Web 目录上执行chmod -R 777结果所有文件都变成任何人可写。一旦站点某个环节被攻破攻击者可以直接改你的代码。正确做法是目录给755文件给644真正需要被写入的上传目录单独设置750或775。如果想要批量按类型区分设置可以配合findfind /opt/app -type d -exec chmod 755 {} \; find /opt/app -type f -exec chmod 644 {} \;这段命令的思路是先给所有目录设一组权限再给所有文件设一组权限两轮搞定比一刀切在目录上递归755干净得多。4.2 符号法u/g/o 加减号数字法虽然快但每次都要完整写出三个组的权限。如果你只是想给属主加上执行权限用数字法很可能不小心把组和其他用户的权限也改了。这时候符号法更精准chmod ux app.sh # 只给属主增加执行权限 chmod g-w config.yaml # 只去掉属组的写权限 chmod o-r private.key # 去除其他用户的读权限 chmod urwx,grx,or app.sh # 直接指定成 754 chmod ar README.md # 所有用户user/group/other都加读符号法里的操作对象是u属主、g属组、o其他、a所有人运算符有加权限、-减权限、直接赋值。我的习惯是做精准调整用符号法批量设置或按完整权限赋值用数字法两者配合基本覆盖所有场景。4.3 修改所有者和属组chown 的常见坑权限不光看 rwx还看文件属于谁。chown用来修改属主和属组常见用法chown alice:devops app.jar # 同时修改属主为 alice、属组为 devops chown alice app.jar # 只修改属主属组不变 chgrp devops app.jar # 只修改属组这里面有几个坑每一个我都见人踩过第一chown基本只有 root 能执行普通用户想把文件改成别人的名字会被拒绝所以实际使用通常要加sudo。第二老教程里会写chown alice.devops点号分隔这种语法现在很多环境已经不认了统一用冒号alice:devops更稳。第三处理符号链接时要小心不加-h参数时chown修改的是链接指向的目标文件而不是链接本身。在打包、迁移目录时这会导致你改了半天软链接还是原属主容易造成混乱。4.4 实战案例部署 Web 目录的权限方案用一个最常见的 LEMP 站点来演示完整方案。假设网站运行用户是www-data开发人员是alice代码目录是/var/www/site。第一步把代码目录授权给 alice 和运行用户组sudo chown -R alice:www-data /var/www/site第二步目录设成750alice 能读写执行www-data组内成员能读和执行其他人一律拒绝sudo find /var/www/site -type d -exec chmod 750 {} \;第三步普通文件设成640alice 能改组内成员能读其他人不可见sudo find /var/www/site -type f -exec chmod 640 {} \;这套方案的好处是开发人员可以正常修改代码Web 服务可以正常读取文件但系统上其他无关用户完全接触不到站点代码。如果后面要增加一个协作者 bob只需要把他加进www-data组不用再动任何权限非常省心。5. 进阶SUID、SGID、粘滞位藏在权限位里的特殊行为5.1 为什么 /usr/bin/passwd 是 rwsr-xr-x 而不是 rwxr-xr-x如果你注意过/usr/bin/passwd这个命令的权限会发现它是-rwsr-xr-x属主权限位的x变成了s。这就是 SUIDSet User ID权限。普通用户要改密码需要写/etc/shadow而这个文件只有 root 才能读。系统怎么让一个普通用户合法地临时获得 root 能力呢办法就是给passwd加上 SUID一个带 SUID 的程序被执行时进程的有效用户 ID 会临时变成文件属主。由于passwd的属主是 root普通用户执行它时这个进程就以 root 身份运行于是能写 shadow 文件但只能做写密码这一件特定的事情。设置 SUID 的方法chmod us program # 等价于 chmod 4755 programSUID 是双刃剑。一个 SUID 程序如果存在漏洞普通用户可能借此提权。排查系统里有哪些 SUID 文件是个好习惯find / -perm -4000 -type f 2/dev/null这条命令会列出所有设置了 SUID 的文件定期看一眼发现异常的多出来的 SUID 文件就要警惕了。5.2 SGID 对目录的作用新文件自动继承属组SGIDSet Group ID在文件上的逻辑和 SUID 类似执行时临时切换有效组。但对目录来说SGID 有个特别实用的作用在该目录下新建的文件或子目录会自动继承目录的属组而不是创建者的默认组。这对团队共享目录非常重要。假设小组共用的目录属组是devs开启了 SGIDchmod gs /shared/dev # 等价于 chmod 2770 /shared/dev之后无论哪个同事在这个目录里新建文件文件的属组都会自动变成devs而不是他个人的私有组。否则你大概率会遇到这种尴尬同事建了个文件你自己在这个共享目录里却读不了因为文件属于他的个人组。设置完成后用ls -l查看目录权限部分会显示drwxrws---组权限位的x变成了s。5.3 /tmp 的粘滞位为什么所有人能建文件却删不掉别人的/tmp目录的权限是drwxrwxrwt最后的t就是 sticky bit粘滞位。/tmp是共享临时目录任何用户都能在里面创建文件所以它的基本权限是777。但如果真的是满777问题就来了任何用户都能删掉别人的临时文件系统会乱成一锅粥。粘滞位专门解决这个问题在设置了粘滞位的目录里只有文件的所有者或 root才能删除、重命名自己创建的文件即使目录本身是777别人也动不了你的文件。设置方法chmod t /some/dir # 等价于 chmod 1777 /some/dir顺便说一个数字权限的经典坑/tmp的正确权限是1777而不是777。很多人写脚本时想当然给了chmod 777 /tmp等于把粘滞位干掉了副作用很大。5.4 特殊权限位与数字法的对应SUID、SGID、粘滞位在数字法里也是有值的放在普通三位数字的前面特殊权限位数字后缀位置显示SUID4属主 x 位变 s/SSGID2属组 x 位变 s/SSticky1其他用户 x 位变 t/T所以4755 SUID rwxr-xr-x2770 SGID rwxrwx---1777 Sticky rwxrwxrwx这里还有个小细节如果对应位置本身没有执行权限那s或t会显示为大写S、T。看到大写字母时说明设置可能不如预期因为大写意味着设置了特殊位但对应位置的 x 权限缺失这种情况特殊位通常不会按你预期的方式生效。6. 遇到 Permission denied按这个顺序排查6.1 五个最常见的排查点Permission denied是 Linux 世界里出现频率最高的报错之一。如果目录和文件权限都写得没问题大多数时候问题出在下面几个方向当前用户或当前进程的用户不在文件属组里目标文件或者它所处的目录缺少对应的 r/w/x从根目录到目标文件的路径链路上某个目录缺少x权限文件被设置了不可变属性chattr i或者被 SELinux/AppArmor 拦截文件系统挂载时带了ro、noexec等限制这里面第 3 点最容易忽略你以为自己在排查目标文件的权限实际上你连到达目标文件的路上就已经被拦住了。我强烈建议遇到权限问题先跑这个命令namei -l /path/to/file它会从根目录开始把路径上每一级目录的权限全部列出来一眼就能看出是哪一层挡住了你。这命令是我权限排障的第一板斧比两眼一抹黑盯着最后一级目录想半天高效太多。6.2 案例一脚本明明有 x 还是执行不了有一次同事写了个部署脚本deploy.shchmod x也执行了ls -l看权限也是-rwxr-xr-x但一运行就报Permission denied。他跑来问我的时候我第一反应是看脚本内容的换行符。在 Windows 上编辑过的脚本换行是 CRLF\r\n而 Linux 脚本要求 LF\n。脚本第一行如果写成#!/bin/bash\r内核会去找一个名字叫/bin/bash\r的解释器找不到于是报错。看起来像权限问题其实是换行符问题。修复方法很简单sed -i s/\r$// deploy.sh # 或者 dos2unix deploy.sh从此之后我遇到权限没问题但执行不了的脚本都会先检查换行符再检查是不是脚本里用了某个没有执行权限的子命令。排障顺序很重要先看报错格式再看权限最后怀疑文件内容本身。另一个容易触发类似现象的是挂载选项。有些分区挂载时带了noexec那上面任何脚本、程序都执行不了但你ls -l看权限一切都正常。确认方式是用mount查看挂载选项或者直接df -h看对应分区。6.3 案例二SSH 公钥登录失败证书权限搞的鬼SSH 登录失败是权限问题的高发区。配置好公钥登录之后连不上日志里往往写着Permissions 0644 for id_rsa are too open意思是私钥权限太宽了。OpenSSH 出于安全考虑对私钥文件和authorized_keys文件的权限有严格要求私钥文件必须只有属主可读写否则任何人能读你的私钥那还谈什么安全。标准权限应该是这样的chmod 700 ~/.ssh chmod 600 ~/.ssh/id_rsa chmod 644 ~/.ssh/id_rsa.pub chmod 600 ~/.ssh/authorized_keys目录~/.ssh的权限也会影响认证设置成700相对保险。很多人在网上拷了公钥配置却忘了检查权限结果折腾半天是权限过宽被 SSH 安全策略拒之门外。这个案例也是权限问题不一定是 rwx 本身的典型代表——安全软件对权限的偏好往往比文件系统的基础权限更苛刻。6.4 案例三容器里挂载目录权限错乱用 Docker 挂载宿主机目录到容器里最常见的权限问题长这样容器内进程以 uid 1000 运行宿主目录却是 root 所有于是容器内写文件就报Permission denied。很多人图省事直接在宿主机上chmod 777挂载目录结果所有容器都能往里写安全隐患很大。更稳妥的做法是让目录属主匹配容器内运行用户的 uid。比如容器内进程是 uid 1000宿主机上就该提前处理mkdir -p /data/app chown -R 1000:1000 /data/app或者反过来在docker run时用--user指定宿主 uid让进程以宿主机上有权限的身份运行。选择哪种方式取决于你的组织和安全要求但核心原则是不变的保证进程的用户身份与目录属主对齐而不是粗暴放大目录权限。说到图形化界面很多刚接触 Linux 的同学入手的是带桌面的发行版比如 UOS 这类国产系统文件管理器右键属性里就有权限设置界面可以直接勾选“读/写/执行”还能切换当前用户、用户组和其他用户的权限。这确实能缓解命令行恐惧但本质上它就是把这串rwxrwxr--翻译成了勾选框。理解了命令行里的规则再用图形工具会发现自己已经在做同一件事——只是换了层皮。我在实际运维里养成的习惯是每次看到权限报错先namei -l看链路再ls -l看当前状态思考哪个用户、在哪个目录、要做什么操作这三个问题最后才是动chmod。权限是有最小适用原则的给多了是风险给少了是故障找到那个刚好够用的位置才是这套rwx规则真正的价值所在。
返回列表